OpenVDB 14.0.0
Loading...
Searching...
No Matches
HostBuffer.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5 @file nanovdb/HostBuffer.h
6
7 @date April 20, 2021
8
9 @brief HostBuffer - a buffer that contains a shared or private bump
10 pool to either externally or internally managed host memory.
11
12 @details This HostBuffer can be used in multiple ways, most of which are
13 demonstrated in the examples below. Memory in the pool can
14 be managed or unmanged (e.g. internal or external) and can
15 be shared between multiple buffers or belong to a single buffer.
16
17 Example that uses HostBuffer::create inside io::readGrids to create a
18 full self-managed buffer, i.e. not shared and without padding, per grid in the file.
19 @code
20 auto handles = nanovdb::io::readGrids("file.nvdb");
21 @endcode
22
23 Example that uses HostBuffer::createFull. Assuming you have a raw pointer
24 to a NanoVDB grid of unknown type, this examples shows how to create its
25 GridHandle which can be used to enquire about the grid type and meta data.
26 @code
27 void *data;// pointer to a NanoVDB grid of unknown type
28 uint64_t size;// byte size of NanoVDB grid of unknown type
29 auto buffer = nanovdb::HostBuffer::createFull(size, data);
30 nanovdb::GridHandle<> gridHandle(std::move(buffer));
31 @endcode
32
33 Example that uses HostBuffer::createPool for internally managed host memory.
34 Suppose you want to read multiple grids in multiple files, but reuse the same
35 fixed sized memory buffer to both avoid memory fragmentation as well as
36 exceeding the fixed memory ceiling!
37 @code
38 auto pool = nanovdb::HostBuffer::createPool(1 << 30);// 1 GB memory pool
39 std::vector<std::string>> frames;// vector of grid names
40 for (int i=0; i<frames.size(); ++i) {
41 auto handles = nanovdb::io::readGrids(frames[i], 0, pool);// throws if grids in file exceed 1 GB
42 ...
43 pool.reset();// clears all handles and resets the memory pool for reuse
44 }
45 @endcode
46
47 Example that uses HostBuffer::createPool for externally managed host memory.
48 Note that in this example @c handles are allowed to outlive @c pool since
49 they internally store a shared pointer to the memory pool. However @c data
50 MUST outlive @c handles since the pool does not own its memory in this example.
51 @code
52 const size_t poolSize = 1 << 30;// 1 GB
53 void *data = std::malloc(size + NANOVDB_DATA_ALIGNMENT);// 1 GB pool with padding
54 void *buffer = nanovdb::alignPtr(data);// 32B aligned buffer
55 //void *buffer = std::aligned_alloc(NANOVDB_DATA_ALIGNMENT, poolSize);// in C++17
56 auto pool = nanovdb::HostBuffer::createPool(poolSize, buffer);
57 auto handles1 = nanovdb::io::readGrids("file1.nvdb", 0, pool);
58 auto handles2 = nanovdb::io::readGrids("file2.nvdb", 0, pool);
59 ....
60 std::free(data);
61 //std::free(buffer);
62 @endcode
63
64 Example that uses HostBuffer::createPool for externally managed host memory.
65 Note that in this example @c handles are allowed to outlive @c pool since
66 they internally store a shared pointer to the memory pool. However @c array
67 MUST outlive @c handles since the pool does not own its memory in this example.
68 @code
69 const size_t poolSize = 1 << 30;// 1 GB
70 std::unique_ptr<char[]> array(new char[size + NANOVDB_DATA_ALIGNMENT]);// scoped pool of 1 GB with padding
71 void *buffer = nanovdb::alignPtr(array.get());// 32B aligned buffer
72 auto pool = nanovdb::HostBuffer::createPool(poolSize, buffer);
73 auto handles = nanovdb::io::readGrids("file.nvdb", 0, pool);
74 @endcode
75*/
76
77#ifndef NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
78#define NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
79
80#include <nanovdb/NanoVDB.h>// for NANOVDB_DATA_ALIGNMENT;
81#include <stdint.h> // for types like int32_t etc
82#include <cstdio> // for fprintf
83#include <cstdlib> // for std::malloc/std::realloc/std::free
84#include <memory>// for std::make_shared
85#include <mutex>// for std::mutex
86#include <unordered_set>// for std::unordered_set
87#include <cassert>// for assert
88#include <sstream>// for std::stringstream
89#include <cstring>// for memcpy
90#include <type_traits>// for std::void_t
91
92#define checkPtr(ptr, msg) \
93 { \
94 ptrAssert((ptr), (msg), __FILE__, __LINE__); \
95 }
96
97namespace nanovdb {
98
99template<typename BufferT>
101{
102 static constexpr bool hasDeviceSingle = false;
103};
104
105/// @brief Detects whether @c BufferTraits<BufferT> defines @c hasDeviceSingle,
106/// i.e. whether the buffer manages a single device-resident allocation.
107/// @details Defaults to false when the trait member is absent, so
108/// BufferTraits specializations (in or out of tree) that do not
109/// define it keep compiling unchanged.
110template<typename BufferT, typename = void>
111struct BufferHasDeviceSingle { static constexpr bool value = false; };
112template<typename BufferT>
113struct BufferHasDeviceSingle<BufferT, std::void_t<decltype(BufferTraits<BufferT>::hasDeviceSingle)>>
115
116/// @brief Companion detection for BufferTraits<...>::hasHostSingle: a
117/// single-space buffer whose storage is host-accessible (e.g. a
118/// pinned-resource cuda::Buffer).
119template<typename BufferT, typename = void>
120struct BufferHasHostSingle { static constexpr bool value = false; };
121template<typename BufferT>
122struct BufferHasHostSingle<BufferT, std::void_t<decltype(BufferTraits<BufferT>::hasHostSingle)>>
123{ static constexpr bool value = BufferTraits<BufferT>::hasHostSingle; };
124
125/// @brief A single-space buffer whose storage the host cannot read: the
126/// device-single family minus its host-accessible members (managed or
127/// pinned resources). This is the predicate that gates the handles'
128/// host accessors off.
129template<typename BufferT>
132
133/// @brief Detects whether a buffer exposes a retained stream (a stream()
134/// member), i.e. whether its resource is stream-ordered. Used to pick
135/// the buffer's stream-taking constructor without naming CUDA types.
136template<typename BufferT, typename = void>
137struct BufferHasStream { static constexpr bool value = false; };
138template<typename BufferT>
139struct BufferHasStream<BufferT, std::void_t<decltype(std::declval<const BufferT&>().stream())>>
140{ static constexpr bool value = true; };
141
142/// @brief Detects whether a buffer's elements are byte-sized. Buffers that
143/// expose no ElementType (e.g. HostBuffer) address raw bytes by
144/// definition, so the primary defaults to true.
145template<typename BufferT, typename = void>
146struct BufferHasByteElements { static constexpr bool value = true; };
147template<typename BufferT>
148struct BufferHasByteElements<BufferT, std::void_t<typename BufferT::ElementType>>
149{ static constexpr bool value = sizeof(typename BufferT::ElementType) == 1; };
150
151/// @brief Detects whether a buffer type is default-constructible, so
152/// consumers can name that requirement in a static_assert instead of
153/// failing wherever the default construction happens to occur.
154template<typename BufferT, typename = void>
155struct BufferIsDefaultConstructible { static constexpr bool value = false; };
156template<typename BufferT>
157struct BufferIsDefaultConstructible<BufferT, std::void_t<decltype(BufferT())>>
158{ static constexpr bool value = true; };
159
160/// @brief Detects whether a buffer provides destroy(), the cuda::Buffer
161/// spelling for releasing its storage. Handle reset() dispatches to it
162/// when present and falls back to the legacy clear() otherwise.
163template<typename BufferT, typename = void>
164struct BufferHasDestroy { static constexpr bool value = false; };
165template<typename BufferT>
166struct BufferHasDestroy<BufferT, std::void_t<decltype(std::declval<BufferT&>().destroy())>>
167{ static constexpr bool value = true; };
168
169// ----------------------------> HostBuffer <--------------------------------------
170
171/// @brief This is a buffer that contains a shared or private pool
172/// to either externally or internally managed host memory.
173///
174/// @note Terminology:
175/// Pool: 0 = buffer.size() < buffer.poolSize()
176/// Buffer: 0 < buffer.size() < buffer.poolSize()
177/// Full: 0 < buffer.size() = buffer.poolSize()
178/// Empty: 0 = buffer.size() = buffer.poolSize()
180{
181 struct Pool;// forward declaration of private pool struct
182 std::shared_ptr<Pool> mPool;
183 uint64_t mSize; // total number of bytes for the NanoVDB grid.
184 void* mData; // raw buffer for the NanoVDB grid.
185
186#if defined(DEBUG) || defined(_DEBUG)
187 static inline void ptrAssert(void* ptr, const char* msg, const char* file, int line, bool abort = true)
188 {
189 if (ptr == nullptr) {
190 fprintf(stderr, "NULL pointer error: %s %s %d\n", msg, file, line);
191 if (abort)
192 exit(1);
193 }
194 if (uint64_t(ptr) % NANOVDB_DATA_ALIGNMENT) {
195 fprintf(stderr, "Alignment pointer error: %s %s %d\n", msg, file, line);
196 if (abort)
197 exit(1);
198 }
199 }
200#else
201 static inline void ptrAssert(void*, const char*, const char*, int, bool = true)
202 {
203 }
204#endif
205
206public:
207 /// @brief Return a full buffer or an empty buffer
208 HostBuffer(uint64_t bufferSize = 0);
209
210 /// @brief Move copy-constructor
211 HostBuffer(HostBuffer&& other);
212
213 /// @brief Custom descructor
214 ~HostBuffer() { this->clear(); }
215
216 /// @brief Move copy assignment operation
218
219 /// @brief Disallow copy-construction
220 HostBuffer(const HostBuffer&) = delete;
221
222 /// @brief Disallow copy assignment operation
223 HostBuffer& operator=(const HostBuffer&) = delete;
224
225 /// @brief Return a pool buffer which satisfies: buffer.size == 0,
226 /// buffer.poolSize() == poolSize, and buffer.data() == nullptr.
227 /// If data==nullptr, memory for the pool will be allocated.
228 ///
229 /// @throw If poolSize is zero.
230 static HostBuffer createPool(uint64_t poolSize, void *data = nullptr);
231
232 /// @brief Return a full buffer which satisfies: buffer.size == bufferSize,
233 /// buffer.poolSize() == bufferSize, and buffer.data() == data.
234 /// If data==nullptr, memory for the pool will be allocated.
235 ///
236 /// @throw If bufferSize is zero.
237 static HostBuffer createFull(uint64_t bufferSize, void *data = nullptr);
238
239 /// @brief Return a buffer with @c bufferSize bytes managed by
240 /// the specified memory @c pool. If none is provided, i.e.
241 /// @c pool == nullptr or @c pool->poolSize() == 0, one is
242 /// created with size @c bufferSize, i.e. a full buffer is returned.
243 ///
244 /// @throw If the specified @c pool has insufficient memory for
245 /// the requested buffer size.
246 static HostBuffer create(uint64_t bufferSize, const HostBuffer* pool = nullptr);
247
248 /// @brief Initialize as a full buffer with the specified size. If data is NULL
249 /// the memory is internally allocated.
250 void init(uint64_t bufferSize, void *data = nullptr);
251
252 //@{
253 /// @brief Retuns a pointer to the raw memory buffer managed by this allocator.
254 ///
255 /// @warning Note that the pointer can be NULL if the allocator was not initialized!
256 const void* data() const { return mData; }
257 void* data() { return mData; }
258 //@}
259
260 /// @brief Returns an offset pointer of a specific type from the allocated host memory
261 /// @tparam T Type of the pointer returned
262 /// @param count Numbers of elements of @c parameter type T to skip
263 /// @warning might return NULL
264 template <typename T>
265 T* data(ptrdiff_t count = 0) const {return mData ? reinterpret_cast<T*>(mData) + count : nullptr;}
266
267 //@{
268 /// @brief Returns the size in bytes associated with this buffer.
269 uint64_t bufferSize() const { return mSize; }
270 uint64_t size() const { return this->bufferSize(); }
271 //@}
272
273 /// @brief Returns the size in bytes of the memory pool shared with this instance.
274 uint64_t poolSize() const;
275
276 /// @brief Return true if memory is managed (using std::malloc and std:free) by the
277 /// shared pool in this buffer. Else memory is assumed to be managed externally.
278 bool isManaged() const;
279
280 //@{
281 /// @brief Returns true if this buffer has no memory associated with it
282 bool isEmpty() const { return !mPool || mSize == 0 || mData == nullptr; }
283 bool empty() const { return this->isEmpty(); }
284 //@}
285
286 /// @brief Return true if this is a pool, i.e. an empty buffer with a nonempty
287 /// internal pool, i.e. this->size() == 0 and this->poolSize() != 0
288 bool isPool() const { return mSize == 0 && this->poolSize() > 0; }
289
290 /// @brief Return true if the pool exists, is nonempty but has no more available memory
291 bool isFull() const;
292
293 /// @brief Clear this buffer so it is empty.
294 void clear();
295
296 /// @brief Clears all existing buffers that are registered against the memory pool
297 /// and resets the pool so it can be reused to create new buffers.
298 ///
299 /// @throw If this instance is not empty or contains no pool.
300 ///
301 /// @warning This method is not thread-safe!
302 void reset();
303
304 /// @brief Total number of bytes from the pool currently in use by buffers
305 uint64_t poolUsage() const;
306
307 /// @brief resize the pool size. It will attempt to resize the existing
308 /// memory block, but if that fails a deep copy is performed.
309 /// If @c data is not NULL it will be used as new externally
310 /// managed memory for the pool. All registered buffers are
311 /// updated so GridHandle::grid might return a new address (if
312 /// deep copy was performed).
313 ///
314 /// @note This method can be use to resize the memory pool and even
315 /// change it from internally to externally managed memory or vice versa.
316 ///
317 /// @throw if @c poolSize is less than this->poolUsage() the used memory
318 /// or allocations fail.
319 void resizePool(uint64_t poolSize, void *data = nullptr);
320
321}; // HostBuffer class
322
323// --------------------------> Implementation of HostBuffer::Pool <------------------------------------
324
325// This is private struct of HostBuffer so you can safely ignore the API
327{
328 using HashTableT = std::unordered_set<HostBuffer*>;
329 std::mutex mMutex; // mutex for updating mRegister and mFree
331 void *mData, *mFree;
332 uint64_t mSize, mPadding;
334
335 /// @brief External memory ctor
336 Pool(uint64_t size = 0, void* data = nullptr)
337 : mData(data)
338 , mFree(mData)
339 , mSize(size)
340 , mPadding(0)
341 , mManaged(data == nullptr)
342 {
343 if (mManaged) {
344 mData = Pool::alloc(mSize);
345 if (mData == nullptr) throw std::runtime_error("Pool::Pool malloc failed");
346 }
348 if (!mManaged && mPadding != 0) {
349 throw std::runtime_error("Pool::Pool: external memory buffer is not aligned to " +
350 std::to_string(NANOVDB_DATA_ALIGNMENT) +
351 " bytes.\nHint: use nanovdb::alignPtr or std::aligned_alloc (C++17 only)");
352 }
354 }
355
356 /// @brief Custom destructor
358 {
359 assert(mRegister.empty());
360 if (mManaged) std::free(mData);
361 }
362
363 /// @brief Disallow copy-construction
364 Pool(const Pool&) = delete;
365
366 /// @brief Disallow move-construction
367 Pool(const Pool&&) = delete;
368
369 /// @brief Disallow copy assignment operation
370 Pool& operator=(const Pool&) = delete;
371
372 /// @brief Disallow move assignment operation
373 Pool& operator=(const Pool&&) = delete;
374
375 /// @brief Return the total number of bytes used from this Pool by buffers
376 uint64_t usage() const { return util::PtrDiff(mFree, mData) - mPadding; }
377
378 /// @brief Allocate a buffer of the specified size and add it to the register
379 void add(HostBuffer* buffer, uint64_t size)
380 {
381 void *alignedFree = util::PtrAdd(mFree, alignmentPadding(mFree));
382
383 if (util::PtrAdd(alignedFree, size) > util::PtrAdd(mData, mPadding + mSize)) {
384 std::stringstream ss;
385 ss << "HostBuffer::Pool: insufficient memory\n"
386 << "\tA buffer requested " << size << " bytes with " << NANOVDB_DATA_ALIGNMENT
387 << "-bytes alignment from a pool with "
388 << mSize << " bytes of which\n\t" << (util::PtrDiff(alignedFree, mData) - mPadding)
389 << " bytes are used by " << mRegister.size() << " other buffer(s). "
390 << "Pool is " << (mManaged ? "internally" : "externally") << " managed.\n";
391 throw std::runtime_error(ss.str());
392 }
393 buffer->mSize = size;
394 const std::lock_guard<std::mutex> lock(mMutex);
395 mRegister.insert(buffer);
396 buffer->mData = alignedFree;
397 mFree = util::PtrAdd(alignedFree, size);
398 }
399
400 /// @brief Remove the specified buffer from the register
401 void remove(HostBuffer *buffer)
402 {
403 const std::lock_guard<std::mutex> lock(mMutex);
404 mRegister.erase(buffer);
405 }
406
407 /// @brief Replaces buffer1 with buffer2 in the register
408 void replace(HostBuffer *buffer1, HostBuffer *buffer2)
409 {
410 const std::lock_guard<std::mutex> lock(mMutex);
411 mRegister.erase( buffer1);
412 mRegister.insert(buffer2);
413 }
414
415 /// @brief Reset the register and all its buffers
416 void reset()
417 {
418 for (HostBuffer *buffer : mRegister) {
419 buffer->mPool.reset();
420 buffer->mSize = 0;
421 buffer->mData = nullptr;
422 }
423 mRegister.clear();
425 }
426
427 /// @brief Resize this Pool and update registered buffers as needed. If data is no NULL
428 /// it is used as externally managed memory.
429 void resize(uint64_t size, void *data = nullptr)
430 {
431 const uint64_t memUsage = this->usage();
432
433 const bool managed = (data == nullptr);
434
435 if (!managed && alignmentPadding(data) != 0) {
436 throw std::runtime_error("Pool::resize: external memory buffer is not aligned to " +
437 std::to_string(NANOVDB_DATA_ALIGNMENT) + " bytes");
438 }
439
440 if (memUsage > size) {
441 throw std::runtime_error("Pool::resize: insufficient memory");
442 }
443
444 uint64_t padding = 0;
445 if (mManaged && managed && size != mSize) { // managed -> managed
446 padding = mPadding;
447 data = Pool::realloc(mData, memUsage, size, padding); // performs both copy and free of mData
448 } else if (!mManaged && managed) { // un-managed -> managed
449 data = Pool::alloc(size);
450 padding = alignmentPadding(data);
451 }
452
453 if (data == nullptr) {
454 throw std::runtime_error("Pool::resize: allocation failed");
455 } else if (data != mData) {
456 void* paddedData = util::PtrAdd(data, padding);
457
458 if (!(mManaged && managed)) { // no need to copy if managed -> managed
459 memcpy(paddedData, util::PtrAdd(mData, mPadding), memUsage);
460 }
461
462 for (HostBuffer* buffer : mRegister) { // update registered buffers
463 buffer->mData = util::PtrAdd(paddedData, util::PtrDiff(buffer->mData, util::PtrAdd(mData, mPadding)));
464 }
465 mFree = util::PtrAdd(paddedData, memUsage); // update the free pointer
466 if (mManaged && !managed) {// only free if managed -> un-managed
467 std::free(mData);
468 }
469
470 mData = data;
471 mPadding = padding;
472 }
473 mSize = size;
474 mManaged = managed;
475 }
476 /// @brief Return true is all the memory in this pool is in use.
477 bool isFull() const
478 {
479 assert(mFree <= util::PtrAdd(mData, mPadding + mSize));
480 return mSize > 0 ? mFree == util::PtrAdd(mData, mPadding + mSize) : false;
481 }
482
483private:
484
485 static void* alloc(uint64_t size)
486 {
487 // make sure we alloc enough space to align the result
488 return std::malloc(size + NANOVDB_DATA_ALIGNMENT);
489 }
490
491 static void* realloc(void* const origData,
492 uint64_t origSize,
493 uint64_t desiredSize,
494 uint64_t& padding)
495 {
496 // make sure we alloc enough space to align the result
497 void* data = std::realloc(origData, desiredSize + NANOVDB_DATA_ALIGNMENT);
498
499 if (data != nullptr && data != origData) {
500 uint64_t newPadding = alignmentPadding(data);
501 // Number of padding bytes may have changed -- move data if that's the case
502 if (newPadding != padding) {
503 // Realloc should not happen when shrinking down buffer, but let's be safe
504 std::memmove(util::PtrAdd(data, newPadding),
505 util::PtrAdd(data, padding),
506 math::Min(origSize, desiredSize));
507 padding = newPadding;
508 }
509 }
510
511 return data;
512 }
513
514};// struct HostBuffer::Pool
515
516// --------------------------> Implementation of HostBuffer <------------------------------------
517
518inline HostBuffer::HostBuffer(uint64_t size) : mPool(nullptr), mSize(size), mData(nullptr)
519{
520 if (size>0) {
521 mPool = std::make_shared<Pool>(size);
522 mData = mPool->mFree;
523 mPool->mRegister.insert(this);
524 mPool->mFree = util::PtrAdd(mPool->mFree, size);
525 }
526}
527
528inline HostBuffer::HostBuffer(HostBuffer&& other) : mPool(other.mPool), mSize(other.mSize), mData(other.mData)
529{
530 if (mPool && mSize != 0) {
531 mPool->replace(&other, this);
532 }
533 other.mPool.reset();
534 other.mSize = 0;
535 other.mData = nullptr;
536}
537
538inline void HostBuffer::init(uint64_t bufferSize, void *data)
539{
540 if (bufferSize == 0) {
541 throw std::runtime_error("HostBuffer: invalid buffer size");
542 }
543 if (mPool) {
544 mPool.reset();
545 }
546 if (!mPool || mPool->mSize != bufferSize) {
547 mPool = std::make_shared<Pool>(bufferSize, data);
548 }
549 mPool->add(this, bufferSize);
550}
551
553{
554 if (mPool) {
555 mPool->remove(this);
556 }
557 mPool = other.mPool;
558 mSize = other.mSize;
559 mData = other.mData;
560 if (mPool && mSize != 0) {
561 mPool->replace(&other, this);
562 }
563 other.mPool.reset();
564 other.mSize = 0;
565 other.mData = nullptr;
566 return *this;
567}
568
569inline uint64_t HostBuffer::poolSize() const
570{
571 return mPool ? mPool->mSize : 0u;
572}
573
574inline uint64_t HostBuffer::poolUsage() const
575{
576 return mPool ? mPool->usage(): 0u;
577}
578
579inline bool HostBuffer::isManaged() const
580{
581 return mPool ? mPool->mManaged : false;
582}
583
584inline bool HostBuffer::isFull() const
585{
586 return mPool ? mPool->isFull() : false;
587}
588
590{
591 if (poolSize == 0) {
592 throw std::runtime_error("HostBuffer: invalid pool size");
593 }
594 HostBuffer buffer;
595 buffer.mPool = std::make_shared<Pool>(poolSize, data);
596 // note the buffer is NOT registered by its pool since it is not using its memory
597 buffer.mSize = 0;
598 buffer.mData = nullptr;
599 return buffer;
600}
601
603{
604 if (bufferSize == 0) {
605 throw std::runtime_error("HostBuffer: invalid buffer size");
606 }
607 HostBuffer buffer;
608 buffer.mPool = std::make_shared<Pool>(bufferSize, data);
609 buffer.mPool->add(&buffer, bufferSize);
610 return buffer;
611}
612
614{
615 HostBuffer buffer;
616 if (pool == nullptr || !pool->mPool) {
617 buffer.mPool = std::make_shared<Pool>(bufferSize);
618 } else {
619 buffer.mPool = pool->mPool;
620 }
621 buffer.mPool->add(&buffer, bufferSize);
622 return buffer;
623}
624
625inline void HostBuffer::clear()
626{
627 if (mPool) {// remove self from the buffer register in the pool
628 mPool->remove(this);
629 }
630 mPool.reset();
631 mSize = 0;
632 mData = nullptr;
633}
634
635inline void HostBuffer::reset()
636{
637 if (this->size()>0) {
638 throw std::runtime_error("HostBuffer: only empty buffers can call reset");
639 }
640 if (!mPool) {
641 throw std::runtime_error("HostBuffer: this buffer contains no pool to reset");
642 }
643 mPool->reset();
644}
645
646inline void HostBuffer::resizePool(uint64_t size, void *data)
647{
648 if (!mPool) {
649 throw std::runtime_error("HostBuffer: this buffer contains no pool to resize");
650 }
651 mPool->resize(size, data);
652}
653
654} // namespace nanovdb
655
656#endif // end of NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
#define NANOVDB_DATA_ALIGNMENT
Definition NanoVDB.h:133
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition HostBuffer.h:180
void * data()
Definition HostBuffer.h:257
~HostBuffer()
Custom descructor.
Definition HostBuffer.h:214
HostBuffer(const HostBuffer &)=delete
Disallow copy-construction.
const void * data() const
Retuns a pointer to the raw memory buffer managed by this allocator.
Definition HostBuffer.h:256
T * data(ptrdiff_t count=0) const
Returns an offset pointer of a specific type from the allocated host memory.
Definition HostBuffer.h:265
HostBuffer(uint64_t bufferSize=0)
Return a full buffer or an empty buffer.
Definition HostBuffer.h:518
HostBuffer & operator=(HostBuffer &&other)
Move copy assignment operation.
Definition HostBuffer.h:552
uint64_t bufferSize() const
Returns the size in bytes associated with this buffer.
Definition HostBuffer.h:269
bool empty() const
Definition HostBuffer.h:283
static HostBuffer createFull(uint64_t bufferSize, void *data=nullptr)
Return a full buffer which satisfies: buffer.size == bufferSize, buffer.poolSize() == bufferSize,...
Definition HostBuffer.h:602
uint64_t poolSize() const
Returns the size in bytes of the memory pool shared with this instance.
Definition HostBuffer.h:569
uint64_t size() const
Definition HostBuffer.h:270
void init(uint64_t bufferSize, void *data=nullptr)
Initialize as a full buffer with the specified size. If data is NULL the memory is internally allocat...
Definition HostBuffer.h:538
HostBuffer & operator=(const HostBuffer &)=delete
Disallow copy assignment operation.
uint64_t poolUsage() const
Total number of bytes from the pool currently in use by buffers.
Definition HostBuffer.h:574
bool isPool() const
Return true if this is a pool, i.e. an empty buffer with a nonempty internal pool,...
Definition HostBuffer.h:288
bool isManaged() const
Return true if memory is managed (using std::malloc and std:free) by the shared pool in this buffer....
Definition HostBuffer.h:579
static HostBuffer create(uint64_t bufferSize, const HostBuffer *pool=nullptr)
Return a buffer with bufferSize bytes managed by the specified memory pool. If none is provided,...
Definition HostBuffer.h:613
void clear()
Clear this buffer so it is empty.
Definition HostBuffer.h:625
bool isEmpty() const
Returns true if this buffer has no memory associated with it.
Definition HostBuffer.h:282
void reset()
Clears all existing buffers that are registered against the memory pool and resets the pool so it can...
Definition HostBuffer.h:635
bool isFull() const
Return true if the pool exists, is nonempty but has no more available memory.
Definition HostBuffer.h:584
void resizePool(uint64_t poolSize, void *data=nullptr)
resize the pool size. It will attempt to resize the existing memory block, but if that fails a deep c...
Definition HostBuffer.h:646
static HostBuffer createPool(uint64_t poolSize, void *data=nullptr)
Return a pool buffer which satisfies: buffer.size == 0, buffer.poolSize() == poolSize,...
Definition HostBuffer.h:589
__hostdev__ constexpr Type Min(Type a, Type b) noexcept
Same-type minimum (the primary template).
Definition Math.h:161
static DstT * PtrAdd(void *p, int64_t offset)
Adds a byte offset to a non-const pointer to produce another non-const pointer.
Definition Util.h:555
static int64_t PtrDiff(const void *p, const void *q)
Compute the distance, in bytes, between two pointers, dist = p - q.
Definition Util.h:541
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:34
static uint64_t alignmentPadding(const void *p)
return the smallest number of bytes that when added to the specified pointer results in a 32 byte ali...
Definition NanoVDB.h:600
Definition Coord.h:590
static void ptrAssert(const void *ptr, const char *msg, const char *file, int line, bool abort=true)
Definition Util.h:32
Detects whether a buffer's elements are byte-sized. Buffers that expose no ElementType (e....
Definition HostBuffer.h:146
static constexpr bool value
Definition HostBuffer.h:146
Detects whether a buffer provides destroy(), the cuda::Buffer spelling for releasing its storage....
Definition HostBuffer.h:164
static constexpr bool value
Definition HostBuffer.h:164
Detects whether BufferTraits<BufferT> defines hasDeviceSingle, i.e. whether the buffer manages a sing...
Definition HostBuffer.h:111
static constexpr bool value
Definition HostBuffer.h:111
Companion detection for BufferTraits<...>::hasHostSingle: a single-space buffer whose storage is host...
Definition HostBuffer.h:120
static constexpr bool value
Definition HostBuffer.h:120
Detects whether a buffer exposes a retained stream (a stream() member), i.e. whether its resource is ...
Definition HostBuffer.h:137
static constexpr bool value
Definition HostBuffer.h:137
Detects whether a buffer type is default-constructible, so consumers can name that requirement in a s...
Definition HostBuffer.h:155
static constexpr bool value
Definition HostBuffer.h:155
A single-space buffer whose storage the host cannot read: the device-single family minus its host-acc...
Definition HostBuffer.h:131
static constexpr bool value
Definition HostBuffer.h:131
Definition HostBuffer.h:101
static constexpr bool hasDeviceSingle
Definition HostBuffer.h:102
Definition HostBuffer.h:327
std::unordered_set< HostBuffer * > HashTableT
Definition HostBuffer.h:328
void resize(uint64_t size, void *data=nullptr)
Resize this Pool and update registered buffers as needed. If data is no NULL it is used as externally...
Definition HostBuffer.h:429
uint64_t usage() const
Return the total number of bytes used from this Pool by buffers.
Definition HostBuffer.h:376
void replace(HostBuffer *buffer1, HostBuffer *buffer2)
Replaces buffer1 with buffer2 in the register.
Definition HostBuffer.h:408
Pool(uint64_t size=0, void *data=nullptr)
External memory ctor.
Definition HostBuffer.h:336
uint64_t mSize
Definition HostBuffer.h:332
void * mData
Definition HostBuffer.h:331
Pool(const Pool &)=delete
Disallow copy-construction.
void add(HostBuffer *buffer, uint64_t size)
Allocate a buffer of the specified size and add it to the register.
Definition HostBuffer.h:379
void remove(HostBuffer *buffer)
Remove the specified buffer from the register.
Definition HostBuffer.h:401
void * mFree
Definition HostBuffer.h:331
Pool & operator=(const Pool &&)=delete
Disallow move assignment operation.
std::mutex mMutex
Definition HostBuffer.h:329
Pool(const Pool &&)=delete
Disallow move-construction.
HashTableT mRegister
Definition HostBuffer.h:330
uint64_t mPadding
Definition HostBuffer.h:332
Pool & operator=(const Pool &)=delete
Disallow copy assignment operation.
void reset()
Reset the register and all its buffers.
Definition HostBuffer.h:416
~Pool()
Custom destructor.
Definition HostBuffer.h:357
bool isFull() const
Return true is all the memory in this pool is in use.
Definition HostBuffer.h:477
bool mManaged
Definition HostBuffer.h:333