mirror of https://github.com/opencv/opencv.git
Merge pull request #16421 from mshabunin:add-local-pool
commit
69944cd46b
4 changed files with 518 additions and 105 deletions
@ -0,0 +1,103 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef OPENCV_UTILS_BUFFER_AREA_HPP |
||||
#define OPENCV_UTILS_BUFFER_AREA_HPP |
||||
|
||||
#include <opencv2/core/base.hpp> |
||||
#include <opencv2/core/private.hpp> |
||||
#include <opencv2/core/utility.hpp> |
||||
#include <vector> |
||||
|
||||
namespace cv { namespace utils { |
||||
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
/** @brief Manages memory block shared by muliple buffers.
|
||||
|
||||
This class allows to allocate one large memory block and split it into several smaller |
||||
non-overlapping buffers. In safe mode each buffer allocation will be performed independently, |
||||
this mode allows dynamic memory access instrumentation using valgrind or memory sanitizer. |
||||
|
||||
Safe mode can be explicitly switched ON in constructor. It will also be enabled when compiling with |
||||
memory sanitizer support or in runtime with the environment variable `OPENCV_BUFFER_AREA_ALWAYS_SAFE`. |
||||
|
||||
Example of usage: |
||||
@code |
||||
int * buf1 = 0; |
||||
double * buf2 = 0; |
||||
cv::util::BufferArea area; |
||||
area.allocate(buf1, 200); // buf1 = new int[200];
|
||||
area.allocate(buf2, 1000, 64); // buf2 = new double[1000]; - aligned by 64
|
||||
area.commit(); |
||||
@endcode |
||||
|
||||
@note This class is considered private and should be used only in OpenCV itself. API can be changed. |
||||
*/ |
||||
class CV_EXPORTS BufferArea |
||||
{ |
||||
public: |
||||
/** @brief Class constructor.
|
||||
|
||||
@param safe Enable _safe_ operation mode, each allocation will be performed independently. |
||||
*/ |
||||
BufferArea(bool safe = false); |
||||
|
||||
/** @brief Class destructor
|
||||
|
||||
All allocated memory well be freed. Each bound pointer will be reset to NULL. |
||||
*/ |
||||
~BufferArea(); |
||||
|
||||
/** @brief Bind a pointer to local area.
|
||||
|
||||
BufferArea will store reference to the pointer and allocation parameters effectively owning the |
||||
pointer and allocated memory. This operation has the same parameters and does the same job |
||||
as the operator `new`, except allocation can be performed later during the BufferArea::commit call. |
||||
|
||||
@param ptr Reference to a pointer of type T. Must be NULL |
||||
@param count Count of objects to be allocated, it has the same meaning as in the operator `new`. |
||||
@param alignment Alignment of allocated memory. same meaning as in the operator `new` (C++17). |
||||
Must be divisible by sizeof(T). Must be power of two. |
||||
|
||||
@note In safe mode allocation will be performed immediatly. |
||||
*/ |
||||
template <typename T> |
||||
void allocate(T*&ptr, size_t count, ushort alignment = sizeof(T)) |
||||
{ |
||||
CV_Assert(ptr == NULL); |
||||
CV_Assert(count > 0); |
||||
CV_Assert(alignment > 0); |
||||
CV_Assert(alignment % sizeof(T) == 0); |
||||
CV_Assert((alignment & (alignment - 1)) == 0); |
||||
allocate_((void**)(&ptr), static_cast<ushort>(sizeof(T)), count, alignment); |
||||
} |
||||
|
||||
/** @brief Allocate memory and initialize all bound pointers
|
||||
|
||||
Each pointer bound to the area with the BufferArea::allocate will be initialized and will be set |
||||
to point to a memory block with requested size and alignment. |
||||
|
||||
@note Does nothing in safe mode as all allocations will be performed by BufferArea::allocate |
||||
*/ |
||||
void commit(); |
||||
|
||||
private: |
||||
BufferArea(const BufferArea &); // = delete
|
||||
BufferArea &operator=(const BufferArea &); // = delete
|
||||
void allocate_(void **ptr, ushort type_size, size_t count, ushort alignment); |
||||
|
||||
private: |
||||
class Block; |
||||
std::vector<Block> blocks; |
||||
void * oneBuf; |
||||
size_t totalSize; |
||||
const bool safe; |
||||
}; |
||||
|
||||
//! @}
|
||||
|
||||
}} // cv::utils::
|
||||
|
||||
#endif |
@ -0,0 +1,121 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "opencv2/core/utils/buffer_area.private.hpp" |
||||
#include "opencv2/core/utils/configuration.private.hpp" |
||||
|
||||
#ifdef OPENCV_ENABLE_MEMORY_SANITIZER |
||||
#define BUFFER_AREA_DEFAULT_MODE true |
||||
#else |
||||
#define BUFFER_AREA_DEFAULT_MODE false |
||||
#endif |
||||
|
||||
static bool CV_BUFFER_AREA_OVERRIDE_SAFE_MODE = |
||||
cv::utils::getConfigurationParameterBool("OPENCV_BUFFER_AREA_ALWAYS_SAFE", BUFFER_AREA_DEFAULT_MODE); |
||||
|
||||
namespace cv { namespace utils { |
||||
|
||||
//==================================================================================================
|
||||
|
||||
class BufferArea::Block |
||||
{ |
||||
private: |
||||
inline size_t reserve_count() const |
||||
{ |
||||
return alignment / type_size - 1; |
||||
} |
||||
public: |
||||
Block(void **ptr_, ushort type_size_, size_t count_, ushort alignment_) |
||||
: ptr(ptr_), raw_mem(0), count(count_), type_size(type_size_), alignment(alignment_) |
||||
{ |
||||
CV_Assert(ptr && *ptr == NULL); |
||||
} |
||||
void cleanup() const |
||||
{ |
||||
CV_Assert(ptr && *ptr); |
||||
*ptr = 0; |
||||
if (raw_mem) |
||||
fastFree(raw_mem); |
||||
} |
||||
size_t getByteCount() const |
||||
{ |
||||
return type_size * (count + reserve_count()); |
||||
} |
||||
void real_allocate() |
||||
{ |
||||
CV_Assert(ptr && *ptr == NULL); |
||||
const size_t allocated_count = count + reserve_count(); |
||||
raw_mem = fastMalloc(type_size * allocated_count); |
||||
if (alignment != type_size) |
||||
{ |
||||
*ptr = alignPtr(raw_mem, alignment); |
||||
CV_Assert(reinterpret_cast<size_t>(*ptr) % alignment == 0); |
||||
CV_Assert(static_cast<uchar*>(*ptr) + type_size * count <= static_cast<uchar*>(raw_mem) + type_size * allocated_count); |
||||
} |
||||
else |
||||
{ |
||||
*ptr = raw_mem; |
||||
} |
||||
} |
||||
void * fast_allocate(void * buf) const |
||||
{ |
||||
CV_Assert(ptr && *ptr == NULL); |
||||
buf = alignPtr(buf, alignment); |
||||
CV_Assert(reinterpret_cast<size_t>(buf) % alignment == 0); |
||||
*ptr = buf; |
||||
return static_cast<void*>(static_cast<uchar*>(*ptr) + type_size * count); |
||||
} |
||||
private: |
||||
void **ptr; |
||||
void * raw_mem; |
||||
size_t count; |
||||
ushort type_size; |
||||
ushort alignment; |
||||
}; |
||||
|
||||
//==================================================================================================
|
||||
|
||||
BufferArea::BufferArea(bool safe_) : |
||||
oneBuf(0), |
||||
totalSize(0), |
||||
safe(safe_ || CV_BUFFER_AREA_OVERRIDE_SAFE_MODE) |
||||
{ |
||||
} |
||||
|
||||
BufferArea::~BufferArea() |
||||
{ |
||||
for(std::vector<Block>::const_iterator i = blocks.begin(); i != blocks.end(); ++i) |
||||
i->cleanup(); |
||||
if (oneBuf) |
||||
fastFree(oneBuf); |
||||
} |
||||
|
||||
void BufferArea::allocate_(void **ptr, ushort type_size, size_t count, ushort alignment) |
||||
{ |
||||
blocks.push_back(Block(ptr, type_size, count, alignment)); |
||||
if (safe) |
||||
blocks.back().real_allocate(); |
||||
else |
||||
totalSize += blocks.back().getByteCount(); |
||||
} |
||||
|
||||
void BufferArea::commit() |
||||
{ |
||||
if (!safe) |
||||
{ |
||||
CV_Assert(totalSize > 0); |
||||
CV_Assert(oneBuf == NULL); |
||||
CV_Assert(!blocks.empty()); |
||||
oneBuf = fastMalloc(totalSize); |
||||
void * ptr = oneBuf; |
||||
for(std::vector<Block>::const_iterator i = blocks.begin(); i != blocks.end(); ++i) |
||||
{ |
||||
ptr = i->fast_allocate(ptr); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//==================================================================================================
|
||||
|
||||
}} // cv::utils::
|
Loading…
Reference in new issue