Open3D (C++ API)  0.13.0
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TBBHashmap.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - Open3D: www.open3d.org -
3 // ----------------------------------------------------------------------------
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2018 www.open3d.org
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // ----------------------------------------------------------------------------
26 
27 #pragma once
28 
29 #include <tbb/concurrent_unordered_map.h>
30 
31 #include <limits>
32 #include <unordered_map>
33 
36 
37 namespace open3d {
38 namespace core {
39 template <typename Key, typename Hash>
40 class TBBHashmap : public DeviceHashmap {
41 public:
42  TBBHashmap(int64_t init_capacity,
43  int64_t dsize_key,
44  int64_t dsize_value,
45  const Device& device);
46  ~TBBHashmap();
47 
48  void Rehash(int64_t buckets) override;
49 
50  void Insert(const void* input_keys,
51  const void* input_values,
52  addr_t* output_addrs,
53  bool* output_masks,
54  int64_t count) override;
55 
56  void Activate(const void* input_keys,
57  addr_t* output_addrs,
58  bool* output_masks,
59  int64_t count) override;
60 
61  void Find(const void* input_keys,
62  addr_t* output_addrs,
63  bool* output_masks,
64  int64_t count) override;
65 
66  void Erase(const void* input_keys,
67  bool* output_masks,
68  int64_t count) override;
69 
70  int64_t GetActiveIndices(addr_t* output_indices) override;
71 
72  void Clear() override;
73 
74  int64_t Size() const override;
75  int64_t GetBucketCount() const override;
76  std::vector<int64_t> BucketSizes() const override;
77  float LoadFactor() const override;
78 
79  std::shared_ptr<tbb::concurrent_unordered_map<Key, addr_t, Hash>> GetImpl()
80  const {
81  return impl_;
82  }
83 
84 protected:
85  std::shared_ptr<tbb::concurrent_unordered_map<Key, addr_t, Hash>> impl_;
86 
87  std::shared_ptr<CPUHashmapBufferAccessor> buffer_ctx_;
88 
89  void InsertImpl(const void* input_keys,
90  const void* input_values,
91  addr_t* output_addrs,
92  bool* output_masks,
93  int64_t count);
94 
95  void Allocate(int64_t capacity);
96 };
97 
98 template <typename Key, typename Hash>
99 TBBHashmap<Key, Hash>::TBBHashmap(int64_t init_capacity,
100  int64_t dsize_key,
101  int64_t dsize_value,
102  const Device& device)
103  : DeviceHashmap(init_capacity, dsize_key, dsize_value, device) {
104  Allocate(init_capacity);
105 }
106 
107 template <typename Key, typename Hash>
109 
110 template <typename Key, typename Hash>
112  return impl_->size();
113 }
114 
115 template <typename Key, typename Hash>
116 void TBBHashmap<Key, Hash>::Insert(const void* input_keys,
117  const void* input_values,
118  addr_t* output_addrs,
119  bool* output_masks,
120  int64_t count) {
121  int64_t new_size = Size() + count;
122  if (new_size > this->capacity_) {
123  int64_t bucket_count = GetBucketCount();
124  float avg_capacity_per_bucket =
125  float(this->capacity_) / float(bucket_count);
126 
127  int64_t expected_buckets = std::max(
128  bucket_count * 2,
129  int64_t(std::ceil(new_size / avg_capacity_per_bucket)));
130 
131  Rehash(expected_buckets);
132  }
133  InsertImpl(input_keys, input_values, output_addrs, output_masks, count);
134 }
135 
136 template <typename Key, typename Hash>
137 void TBBHashmap<Key, Hash>::Activate(const void* input_keys,
138  addr_t* output_addrs,
139  bool* output_masks,
140  int64_t count) {
141  Insert(input_keys, nullptr, output_addrs, output_masks, count);
142 }
143 
144 template <typename Key, typename Hash>
145 void TBBHashmap<Key, Hash>::Find(const void* input_keys,
146  addr_t* output_addrs,
147  bool* output_masks,
148  int64_t count) {
149  const Key* input_keys_templated = static_cast<const Key*>(input_keys);
150 
151 #pragma omp parallel for
152  for (int64_t i = 0; i < count; ++i) {
153  const Key& key = input_keys_templated[i];
154 
155  auto iter = impl_->find(key);
156  bool flag = (iter != impl_->end());
157  output_masks[i] = flag;
158  output_addrs[i] = flag ? iter->second : 0;
159  }
160 }
161 
162 template <typename Key, typename Hash>
163 void TBBHashmap<Key, Hash>::Erase(const void* input_keys,
164  bool* output_masks,
165  int64_t count) {
166  const Key* input_keys_templated = static_cast<const Key*>(input_keys);
167 
168  for (int64_t i = 0; i < count; ++i) {
169  const Key& key = input_keys_templated[i];
170 
171  auto iter = impl_->find(key);
172  bool flag = (iter != impl_->end());
173  output_masks[i] = flag;
174  if (flag) {
175  buffer_ctx_->DeviceFree(iter->second);
176  impl_->unsafe_erase(iter);
177  }
178  }
179 }
180 
181 template <typename Key, typename Hash>
183  int64_t count = impl_->size();
184  int64_t i = 0;
185  for (auto iter = impl_->begin(); iter != impl_->end(); ++iter, ++i) {
186  output_indices[i] = static_cast<int64_t>(iter->second);
187  }
188 
189  return count;
190 }
191 
192 template <typename Key, typename Hash>
194  impl_->clear();
195  buffer_ctx_->Reset();
196 }
197 
198 template <typename Key, typename Hash>
199 void TBBHashmap<Key, Hash>::Rehash(int64_t buckets) {
200  int64_t iterator_count = Size();
201 
202  Tensor active_keys;
203  Tensor active_values;
204 
205  if (iterator_count > 0) {
206  Tensor active_addrs({iterator_count}, Dtype::Int32, this->device_);
207  GetActiveIndices(static_cast<addr_t*>(active_addrs.GetDataPtr()));
208 
209  Tensor active_indices = active_addrs.To(Dtype::Int64);
210  active_keys = this->GetKeyBuffer().IndexGet({active_indices});
211  active_values = this->GetValueBuffer().IndexGet({active_indices});
212  }
213 
214  float avg_capacity_per_bucket =
215  float(this->capacity_) / float(GetBucketCount());
216  int64_t new_capacity =
217  int64_t(std::ceil(buckets * avg_capacity_per_bucket));
218 
219  Allocate(new_capacity);
220 
221  if (iterator_count > 0) {
222  Tensor output_addrs({iterator_count}, Dtype::Int32, this->device_);
223  Tensor output_masks({iterator_count}, Dtype::Bool, this->device_);
224 
225  InsertImpl(active_keys.GetDataPtr(), active_values.GetDataPtr(),
226  static_cast<addr_t*>(output_addrs.GetDataPtr()),
227  output_masks.GetDataPtr<bool>(), iterator_count);
228  }
229 
230  impl_->rehash(buckets);
231 }
232 
233 template <typename Key, typename Hash>
235  return impl_->unsafe_bucket_count();
236 }
237 
238 template <typename Key, typename Hash>
239 std::vector<int64_t> TBBHashmap<Key, Hash>::BucketSizes() const {
240  int64_t bucket_count = impl_->unsafe_bucket_count();
241  std::vector<int64_t> ret;
242  for (int64_t i = 0; i < bucket_count; ++i) {
243  ret.push_back(impl_->unsafe_bucket_size(i));
244  }
245  return ret;
246 }
247 
248 template <typename Key, typename Hash>
250  return impl_->load_factor();
251 }
252 
253 template <typename Key, typename Hash>
254 void TBBHashmap<Key, Hash>::InsertImpl(const void* input_keys,
255  const void* input_values,
256  addr_t* output_addrs,
257  bool* output_masks,
258  int64_t count) {
259  const Key* input_keys_templated = static_cast<const Key*>(input_keys);
260 
261 #pragma omp parallel for
262  for (int64_t i = 0; i < count; ++i) {
263  output_addrs[i] = 0;
264  output_masks[i] = false;
265 
266  const Key& key = input_keys_templated[i];
267 
268  // Try to insert a dummy address.
269  auto res = impl_->insert({key, 0});
270 
271  // Lazy copy key value pair to buffer only if succeeded
272  if (res.second) {
273  addr_t dst_kv_addr = buffer_ctx_->DeviceAllocate();
274  auto dst_kv_iter = buffer_ctx_->ExtractIterator(dst_kv_addr);
275 
276  // Copy templated key to buffer
277  *static_cast<Key*>(dst_kv_iter.first) = key;
278 
279  // Copy/reset non-templated value in buffer
280  uint8_t* dst_value = static_cast<uint8_t*>(dst_kv_iter.second);
281  if (input_values != nullptr) {
282  const uint8_t* src_value =
283  static_cast<const uint8_t*>(input_values) +
284  this->dsize_value_ * i;
285  std::memcpy(dst_value, src_value, this->dsize_value_);
286  } else {
287  std::memset(dst_value, 0, this->dsize_value_);
288  }
289 
290  // Update from dummy 0
291  res.first->second = dst_kv_addr;
292 
293  // Write to return variables
294  output_addrs[i] = dst_kv_addr;
295  output_masks[i] = true;
296  }
297  }
298 }
299 
300 template <typename Key, typename Hash>
301 void TBBHashmap<Key, Hash>::Allocate(int64_t capacity) {
302  this->capacity_ = capacity;
303 
304  this->buffer_ =
305  std::make_shared<HashmapBuffer>(this->capacity_, this->dsize_key_,
306  this->dsize_value_, this->device_);
307 
308  buffer_ctx_ = std::make_shared<CPUHashmapBufferAccessor>(
309  this->capacity_, this->dsize_key_, this->dsize_value_,
310  this->buffer_->GetKeyBuffer(), this->buffer_->GetValueBuffer(),
311  this->buffer_->GetHeap());
312  buffer_ctx_->Reset();
313 
314  impl_ = std::make_shared<tbb::concurrent_unordered_map<Key, addr_t, Hash>>(
315  capacity, Hash());
316 }
317 
318 } // namespace core
319 } // namespace open3d
float LoadFactor() const override
Definition: TBBHashmap.h:249
void Clear() override
Clear stored map without reallocating memory.
Definition: TBBHashmap.h:193
std::vector< int64_t > BucketSizes() const override
Definition: TBBHashmap.h:239
void Find(const void *input_keys, addr_t *output_addrs, bool *output_masks, int64_t count) override
Parallel find a contiguous array of keys.
Definition: TBBHashmap.h:145
void Erase(const void *input_keys, bool *output_masks, int64_t count) override
Parallel erase a contiguous array of keys.
Definition: TBBHashmap.h:163
std::shared_ptr< tbb::concurrent_unordered_map< Key, addr_t, Hash > > GetImpl() const
Definition: TBBHashmap.h:79
void Allocate(int64_t capacity)
Definition: TBBHashmap.h:301
FN_SPECIFIERS MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:108
int64_t Size() const override
Definition: TBBHashmap.h:111
std::shared_ptr< CPUHashmapBufferAccessor > buffer_ctx_
Definition: TBBHashmap.h:87
void Activate(const void *input_keys, addr_t *output_addrs, bool *output_masks, int64_t count) override
Definition: TBBHashmap.h:137
Definition: DeviceHashmap.h:39
void Rehash(int64_t buckets) override
Definition: TBBHashmap.h:199
int64_t GetBucketCount() const override
Definition: TBBHashmap.h:234
static const Dtype Int32
Definition: Dtype.h:46
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter.
Definition: Tensor.cpp:704
~TBBHashmap()
Definition: TBBHashmap.h:108
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:540
Device device_
Definition: DeviceHashmap.h:113
Definition: Device.h:39
int count
Definition: FilePCD.cpp:61
void InsertImpl(const void *input_keys, const void *input_values, addr_t *output_addrs, bool *output_masks, int64_t count)
Definition: TBBHashmap.h:254
void Insert(const void *input_keys, const void *input_values, addr_t *output_addrs, bool *output_masks, int64_t count) override
Parallel insert contiguous arrays of keys and values.
Definition: TBBHashmap.h:116
std::shared_ptr< tbb::concurrent_unordered_map< Key, addr_t, Hash > > impl_
Definition: TBBHashmap.h:85
static const Dtype Int64
Definition: Dtype.h:47
Definition: PinholeCameraIntrinsic.cpp:35
TBBHashmap(int64_t init_capacity, int64_t dsize_key, int64_t dsize_value, const Device &device)
Definition: TBBHashmap.h:99
Definition: Tensor.h:50
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t timeout_in_ms capture_handle capture_handle capture_handle image_handle float
Definition: K4aPlugin.cpp:465
int64_t capacity_
Definition: DeviceHashmap.h:109
Tensor & GetKeyBuffer()
Definition: DeviceHashmap.h:101
uint32_t addr_t
Definition: HashmapBuffer.h:58
int64_t dsize_key_
Definition: DeviceHashmap.h:110
T * GetDataPtr()
Definition: Tensor.h:1005
Definition: TBBHashmap.h:40
static const Dtype Bool
Definition: Dtype.h:52
int64_t GetActiveIndices(addr_t *output_indices) override
Parallel collect all iterators in the hash table.
Definition: TBBHashmap.h:182
int64_t dsize_value_
Definition: DeviceHashmap.h:111
Tensor & GetValueBuffer()
Definition: DeviceHashmap.h:102
std::shared_ptr< HashmapBuffer > buffer_
Definition: DeviceHashmap.h:115
#define max(x, y)
Definition: SVD3x3CPU.h:38