HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
instanceRegistry.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_IMAGING_HD_INSTANCE_REGISTRY_H
8 #define PXR_IMAGING_HD_INSTANCE_REGISTRY_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/imaging/hd/api.h"
12 #include "pxr/imaging/hd/version.h"
13 #include "pxr/imaging/hd/perfLog.h"
14 #include "pxr/imaging/hf/perfLog.h"
15 
16 #include <tbb/concurrent_unordered_map.h>
17 
18 #include <memory>
19 #include <mutex>
20 
22 
23 
24 /// \class HdInstance
25 ///
26 /// This class is used as an interface to a shared instance in
27 /// HdInstanceRegistry.
28 ///
29 /// KeyType is a hashable index type and VALUE is shared_ptr. In most use
30 /// cases, the client computes a hash key which represents large bulky data
31 /// (like topology, primvars) and registers it into HdInstanceRegistry. If the
32 /// key has already been registered, the registry returns HdInstance and the
33 /// client can use GetValue() without setting/computing actual bulky data. If
34 /// it doesn't exist, IsFirstInstance() returns true for the first instance
35 /// and the client needs to populate an appropriate data VALUE into the
36 /// instance by SetValue().
37 ///
38 /// In order to support concurrent access to HdInstanceRegistry, this
39 /// class holds a lock to a mutex in HdInstanceRegistry. This lock will
40 /// be held until the instance of this interface class is destroyed.
41 ///
42 template <typename VALUE>
43 class HdInstance {
44 public:
45  typedef uint64_t KeyType;
46  typedef VALUE ValueType;
47 
48  typedef KeyType ID;
49 
50  struct ValueHolder {
52  : value(value)
53  , recycleCounter(0)
54  { }
56  recycleCounter = 0;
57  }
58 
61  };
62  typedef tbb::concurrent_unordered_map<KeyType, ValueHolder> Dictionary;
63 
64  typedef std::mutex RegistryMutex;
65  typedef std::unique_lock<RegistryMutex> RegistryLock;
66 
67  HdInstance() = delete;
68 
69  /// Construct an instance holding a registry lock, representing a value
70  /// held in a registry container.
71  explicit HdInstance(KeyType const &key,
72  ValueType const &value,
73  RegistryLock &&registryLock,
74  Dictionary *container)
75  : _key(key)
76  , _value(value)
77  , _registryLock(std::move(registryLock))
78  , _container(container)
79  , _isFirstInstance(!bool(_value))
80  { }
81 
82  /// Construct an instance with no lock or registry container. This
83  /// is used to present a consistent interface to clients in cases
84  /// where shared resource registration is disabled.
85  explicit HdInstance(KeyType const &key)
86  : _key(key)
87  , _value(ValueType())
88  , _registryLock()
89  , _container(nullptr)
90  , _isFirstInstance(!bool(_value))
91  { }
92 
93  /// Returns the key
94  KeyType const &GetKey() const { return _key; }
95 
96  /// Returns the value
97  ValueType const &GetValue() const { return _value; }
98 
99  /// Update the value in dictionary indexed by the key.
100  void SetValue(ValueType const &value) {
101  if (_container) (*_container)[_key] = ValueHolder(value);
102  _value = value;
103  }
104 
105  /// Returns true if the value has not been initialized.
106  bool IsFirstInstance() const {
107  return _isFirstInstance;
108  }
109 
110 private:
111  KeyType _key;
112  ValueType _value;
113  RegistryLock _registryLock;
114  Dictionary *_container;
115  bool _isFirstInstance;
116 };
117 
118 /// \class HdInstanceRegistry
119 ///
120 /// HdInstanceRegistry is a dictionary container of HdInstance.
121 /// This class is almost just a dictionary from key to value.
122 /// For cleaning unused entries, it provides GarbageCollect() API.
123 /// It sweeps all entries in the dictionary and erase unreferenced entries.
124 /// When HdInstance::ValueType is shared_ptr, it is regarded as unreferenced
125 /// if the shared_ptr is unique (use_count==1). Note that Key is not
126 /// involved to determine the lifetime of entries.
127 ///
128 template <typename VALUE>
130 public:
132 
133  HdInstanceRegistry() = default;
134 
135  /// Copy constructor. Need as HdInstanceRegistry is placed in a map
136  /// and mutex is not copy constructable, so can't use default
138  : _dictionary(other._dictionary)
139  , _registryMutex() // mutex is not copied
140  { }
141 
142  /// Returns a shared instance for given key.
144  typename InstanceType::KeyType const &key);
145 
146  /// Returns a shared instance for a given key
147  /// only if the key exists in the dictionary.
149  typename InstanceType::KeyType const &key, bool *found);
150 
151  /// Removes unreferenced entries and returns the count
152  /// of remaining entries. When recycleCount is greater than zero,
153  /// unreferenced entries will not be removed until GarbageCollect() is
154  /// called that many more times, i.e. allowing unreferenced entries to
155  /// be recycled if they are needed again.
156  size_t GarbageCollect(int recycleCount = 0);
157 
158  /// Removes unreferenced entries and returns the count
159  /// of remaining entries. If an entry is to be removed, callback function
160  /// "callback" will be called on the entry before removal. When
161  /// recycleCount is greater than zero, unreferenced entries will not be
162  /// removed until GarbageCollect() is called that many more times, i.e.
163  /// allowing unreferenced entries to be recycled if they are needed again.
164  template <typename Callback>
165  size_t GarbageCollect(Callback &&callback, int recycleCount = 0);
166 
167  /// Returns a const iterator being/end of dictionary. Mainly used for
168  /// resource auditing.
169  typedef typename InstanceType::Dictionary::const_iterator const_iterator;
170  const_iterator begin() const { return _dictionary.begin(); }
171  const_iterator end() const { return _dictionary.end(); }
172 
173  size_t size() const { return _dictionary.size(); }
174 
175  void Invalidate();
176 
177 private:
178  template <typename T>
179  static bool _IsUnique(std::shared_ptr<T> const &value) {
180  return value.use_count() == 1;
181  }
182 
183  typename InstanceType::Dictionary _dictionary;
184  typename InstanceType::RegistryMutex _registryMutex;
185 
186  HdInstanceRegistry &operator =(HdInstanceRegistry &) = delete;
187 };
188 
189 // ---------------------------------------------------------------------------
190 // instance registry impl
191 
192 template <typename VALUE>
195  typename HdInstance<VALUE>::KeyType const &key)
196 {
199 
200  // Grab Registry lock
201  // (and don't release it in this function, return it instead)
202  typename InstanceType::RegistryLock lock(_registryMutex);
203 
204  typename InstanceType::Dictionary::iterator it = _dictionary.find(key);
205  if (it == _dictionary.end()) {
206  // not found. create new one
207  it = _dictionary.insert(
208  std::make_pair(key, typename InstanceType::ValueHolder())).first;
209  }
210 
211  it->second.ResetRecycleCounter();
212  return InstanceType(key, it->second.value, std::move(lock), &_dictionary);
213 }
214 
215 template <typename VALUE>
218  typename HdInstance<VALUE>::KeyType const &key, bool *found)
219 {
222 
223  // Grab Registry lock
224  // (and don't release it in this function, return it instead)
225  typename InstanceType::RegistryLock lock(_registryMutex);
226 
227  typename InstanceType::Dictionary::iterator it = _dictionary.find(key);
228  if (it == _dictionary.end()) {
229  *found = false;
230  return InstanceType(key, VALUE(), std::move(lock), nullptr);
231  } else {
232  *found = true;
233  it->second.ResetRecycleCounter();
234  return InstanceType(key, it->second.value,std::move(lock),&_dictionary);
235  }
236 }
237 
238 template <typename VALUE>
239 size_t
241 {
242  // Call GarbageCollect with empty callback function
243  return GarbageCollect([](void*){}, recycleCount);
244 }
245 
246 template <typename VALUE>
247 template <typename Callback>
248 size_t
249 HdInstanceRegistry<VALUE>::GarbageCollect(Callback &&callback, int recycleCount)
250 {
253 
254  // Skip garbage collection entirely when then the recycleCount is < 0
255  if (recycleCount < 0) {
256  return _dictionary.size();
257  }
258 
259  size_t inUseCount = 0;
260  for (typename InstanceType::Dictionary::iterator it = _dictionary.begin();
261  it != _dictionary.end();) {
262 
263  // erase instance which isn't referred from anyone
264  bool isUnique = _IsUnique(it->second.value);
265  if (isUnique && (++it->second.recycleCounter > recycleCount)) {
266  std::forward<Callback>(callback)(it->second.value.get());
267  it = _dictionary.unsafe_erase(it);
268  } else {
269  ++it;
270  ++inUseCount;
271  }
272  }
273  return inUseCount;
274 }
275 
276 template <typename VALUE>
277 void
279 {
282 
283  _dictionary.clear();
284 }
285 
286 
288 
289 #endif // PXR_IMAGING_HD_INSTANCE_REGISTRY_H
size_t GarbageCollect(int recycleCount=0)
tbb::concurrent_unordered_map< KeyType, ValueHolder > Dictionary
KeyType const & GetKey() const
Returns the key.
HdInstance()=delete
GLsizei const GLfloat * value
Definition: glcorearb.h:824
#define HF_MALLOC_TAG_FUNCTION()
Definition: perfLog.h:20
uint64_t KeyType
const_iterator begin() const
bool IsFirstInstance() const
Returns true if the value has not been initialized.
HdInstanceRegistry()=default
HdInstance< VALUE > InstanceType
OutGridT const XformOp bool bool
HdInstance(KeyType const &key)
void SetValue(ValueType const &value)
Update the value in dictionary indexed by the key.
HdInstance(KeyType const &key, ValueType const &value, RegistryLock &&registryLock, Dictionary *container)
InstanceType::Dictionary::const_iterator const_iterator
#define HD_TRACE_FUNCTION()
Definition: perfLog.h:40
std::unique_lock< RegistryMutex > RegistryLock
HdInstanceRegistry(const HdInstanceRegistry &other)
InstanceType GetInstance(typename InstanceType::KeyType const &key)
Returns a shared instance for given key.
std::mutex RegistryMutex
size_t size() const
ValueType const & GetValue() const
Returns the value.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
InstanceType FindInstance(typename InstanceType::KeyType const &key, bool *found)
ValueHolder(ValueType const &value=ValueType())
const_iterator end() const