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