Skip to content

Commit 64629cb

Browse files
committed
Merge pull request opencv#12783 from alalek:test_tag
2 parents 5f50069 + e0841f3 commit 64629cb

22 files changed

+1027
-29
lines changed

modules/core/include/opencv2/core/private.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,20 @@ namespace cv
141141
{
142142
CV_EXPORTS void scalarToRawData(const cv::Scalar& s, void* buf, int type, int unroll_to = 0);
143143

144-
//! Allocate all memory buffers which will not be freed, ease filtering memcheck issues
144+
//! Allocate memory buffers which will not be freed, ease filtering memcheck issues. Uses fastMalloc() call.
145145
CV_EXPORTS void* allocSingletonBuffer(size_t size);
146146

147-
//! Allocate all memory buffers which will not be freed, ease filtering memcheck issues
147+
//! Allocate memory buffers which will not be freed, ease filtering memcheck issues. Uses fastMalloc() call
148148
template <typename T> static inline
149149
T* allocSingleton(size_t count = 1) { return static_cast<T*>(allocSingletonBuffer(sizeof(T) * count)); }
150150

151+
//! Allocate memory buffers which will not be freed, ease filtering memcheck issues. Uses generic malloc() call.
152+
CV_EXPORTS void* allocSingletonNewBuffer(size_t size);
153+
154+
//! Allocate memory buffers which will not be freed, ease filtering memcheck issues. Uses generic malloc() call.
155+
template <typename T> static inline
156+
T* allocSingletonNew() { return new(allocSingletonNewBuffer(sizeof(T))) T(); }
157+
151158
} // namespace
152159

153160
#if 1 // TODO: Remove in OpenCV 4.x
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#ifndef OPENCV_CORE_ALLOCATOR_STATS_HPP
6+
#define OPENCV_CORE_ALLOCATOR_STATS_HPP
7+
8+
#include "../cvdef.h"
9+
10+
namespace cv { namespace utils {
11+
12+
class AllocatorStatisticsInterface
13+
{
14+
protected:
15+
AllocatorStatisticsInterface() {}
16+
virtual ~AllocatorStatisticsInterface() {}
17+
public:
18+
virtual uint64_t getCurrentUsage() const = 0;
19+
virtual uint64_t getTotalUsage() const = 0;
20+
virtual uint64_t getNumberOfAllocations() const = 0;
21+
virtual uint64_t getPeakUsage() const = 0;
22+
23+
/** set peak usage = current usage */
24+
virtual void resetPeakUsage() = 0;
25+
};
26+
27+
}} // namespace
28+
29+
#endif // OPENCV_CORE_ALLOCATOR_STATS_HPP
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#ifndef OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP
6+
#define OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP
7+
8+
#include "./allocator_stats.hpp"
9+
10+
#ifdef CV_CXX11
11+
#include <atomic>
12+
#endif
13+
14+
namespace cv { namespace utils {
15+
16+
#ifdef CV__ALLOCATOR_STATS_LOG
17+
namespace {
18+
#endif
19+
20+
class AllocatorStatistics : public AllocatorStatisticsInterface
21+
{
22+
protected:
23+
#ifdef CV_CXX11
24+
std::atomic<long long> curr, total, total_allocs, peak;
25+
#else
26+
volatile long long curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only
27+
#endif
28+
29+
public:
30+
AllocatorStatistics()
31+
#ifndef CV_CXX11
32+
: curr(0), total(0), total_allocs(0), peak(0)
33+
#endif
34+
{}
35+
~AllocatorStatistics() CV_OVERRIDE {}
36+
37+
// AllocatorStatisticsInterface
38+
39+
#ifdef CV_CXX11
40+
uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr.load(); }
41+
uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total.load(); }
42+
uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs.load(); }
43+
uint64_t getPeakUsage() const CV_OVERRIDE { return (uint64_t)peak.load(); }
44+
45+
/** set peak usage = current usage */
46+
void resetPeakUsage() CV_OVERRIDE { peak.store(curr.load()); }
47+
48+
// Controller interface
49+
void onAllocate(size_t sz)
50+
{
51+
#ifdef CV__ALLOCATOR_STATS_LOG
52+
CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load()));
53+
#endif
54+
55+
long long new_curr = curr.fetch_add((long long)sz) + (long long)sz;
56+
57+
// peak = std::max((uint64_t)peak, new_curr);
58+
auto prev_peak = peak.load();
59+
while (prev_peak < new_curr)
60+
{
61+
if (peak.compare_exchange_weak(prev_peak, new_curr))
62+
break;
63+
}
64+
// end of peak = max(...)
65+
66+
total += (long long)sz;
67+
total_allocs++;
68+
}
69+
void onFree(size_t sz)
70+
{
71+
#ifdef CV__ALLOCATOR_STATS_LOG
72+
CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load()));
73+
#endif
74+
curr -= (long long)sz;
75+
}
76+
77+
#else
78+
uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr; }
79+
uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total; }
80+
uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs; }
81+
uint64_t getPeakUsage() const CV_OVERRIDE { return (uint64_t)peak; }
82+
83+
void resetPeakUsage() CV_OVERRIDE { peak = curr; }
84+
85+
// Controller interface
86+
void onAllocate(size_t sz)
87+
{
88+
#ifdef CV__ALLOCATOR_STATS_LOG
89+
CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr));
90+
#endif
91+
92+
uint64_t new_curr = (uint64_t)CV_XADD(&curr, (uint64_t)sz) + sz;
93+
94+
peak = std::max((uint64_t)peak, new_curr); // non-thread safe
95+
96+
//CV_XADD(&total, (uint64_t)sz); // overflow with int, non-reliable...
97+
total += sz;
98+
99+
CV_XADD(&total_allocs, (uint64_t)1);
100+
}
101+
void onFree(size_t sz)
102+
{
103+
#ifdef CV__ALLOCATOR_STATS_LOG
104+
CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr));
105+
#endif
106+
CV_XADD(&curr, (uint64_t)-sz);
107+
}
108+
#endif
109+
};
110+
111+
#ifdef CV__ALLOCATOR_STATS_LOG
112+
} // namespace
113+
#endif
114+
115+
}} // namespace
116+
117+
#endif // OPENCV_CORE_ALLOCATOR_STATS_IMPL_HPP

modules/core/src/alloc.cpp

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,51 @@
4242

4343
#include "precomp.hpp"
4444

45+
#include <opencv2/core/utils/logger.defines.hpp>
46+
#undef CV_LOG_STRIP_LEVEL
47+
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
48+
#include <opencv2/core/utils/logger.hpp>
49+
50+
#define CV__ALLOCATOR_STATS_LOG(...) CV_LOG_VERBOSE(NULL, 0, "alloc.cpp: " << __VA_ARGS__)
51+
#include "opencv2/core/utils/allocator_stats.impl.hpp"
52+
#undef CV__ALLOCATOR_STATS_LOG
53+
54+
//#define OPENCV_ALLOC_ENABLE_STATISTICS
55+
#define OPENCV_ALLOC_STATISTICS_LIMIT 4096 // don't track buffers less than N bytes
56+
57+
4558
#ifdef HAVE_POSIX_MEMALIGN
4659
#include <stdlib.h>
4760
#elif defined HAVE_MALLOC_H
4861
#include <malloc.h>
4962
#endif
5063

64+
#ifdef OPENCV_ALLOC_ENABLE_STATISTICS
65+
#include <map>
66+
#endif
67+
5168
namespace cv {
5269

5370
static void* OutOfMemoryError(size_t size)
5471
{
5572
CV_Error_(CV_StsNoMem, ("Failed to allocate %llu bytes", (unsigned long long)size));
5673
}
5774

75+
CV_EXPORTS cv::utils::AllocatorStatisticsInterface& getAllocatorStatistics();
76+
77+
static cv::utils::AllocatorStatistics allocator_stats;
78+
79+
cv::utils::AllocatorStatisticsInterface& getAllocatorStatistics()
80+
{
81+
return allocator_stats;
82+
}
5883

59-
void* fastMalloc( size_t size )
84+
#ifdef OPENCV_ALLOC_ENABLE_STATISTICS
85+
static inline
86+
void* fastMalloc_(size_t size)
87+
#else
88+
void* fastMalloc(size_t size)
89+
#endif
6090
{
6191
#ifdef HAVE_POSIX_MEMALIGN
6292
void* ptr = NULL;
@@ -80,7 +110,12 @@ void* fastMalloc( size_t size )
80110
#endif
81111
}
82112

113+
#ifdef OPENCV_ALLOC_ENABLE_STATISTICS
114+
static inline
115+
void fastFree_(void* ptr)
116+
#else
83117
void fastFree(void* ptr)
118+
#endif
84119
{
85120
#if defined HAVE_POSIX_MEMALIGN || defined HAVE_MEMALIGN
86121
free(ptr);
@@ -95,6 +130,47 @@ void fastFree(void* ptr)
95130
#endif
96131
}
97132

133+
#ifdef OPENCV_ALLOC_ENABLE_STATISTICS
134+
135+
static
136+
Mutex& getAllocationStatisticsMutex()
137+
{
138+
static Mutex* p_alloc_mutex = allocSingletonNew<Mutex>();
139+
CV_Assert(p_alloc_mutex);
140+
return *p_alloc_mutex;
141+
}
142+
143+
static std::map<void*, size_t> allocated_buffers; // guarded by getAllocationStatisticsMutex()
144+
145+
void* fastMalloc(size_t size)
146+
{
147+
void* res = fastMalloc_(size);
148+
if (res && size >= OPENCV_ALLOC_STATISTICS_LIMIT)
149+
{
150+
cv::AutoLock lock(getAllocationStatisticsMutex());
151+
allocated_buffers.insert(std::make_pair(res, size));
152+
allocator_stats.onAllocate(size);
153+
}
154+
return res;
155+
}
156+
157+
void fastFree(void* ptr)
158+
{
159+
{
160+
cv::AutoLock lock(getAllocationStatisticsMutex());
161+
std::map<void*, size_t>::iterator i = allocated_buffers.find(ptr);
162+
if (i != allocated_buffers.end())
163+
{
164+
size_t size = i->second;
165+
allocator_stats.onFree(size);
166+
allocated_buffers.erase(i);
167+
}
168+
}
169+
fastFree_(ptr);
170+
}
171+
172+
#endif // OPENCV_ALLOC_ENABLE_STATISTICS
173+
98174
} // namespace
99175

100176
CV_IMPL void* cvAlloc( size_t size )

modules/core/src/ocl.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454

5555
#include <opencv2/core/utils/configuration.private.hpp>
5656

57+
#include <opencv2/core/utils/logger.defines.hpp>
58+
#undef CV_LOG_STRIP_LEVEL
59+
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1
5760
#include <opencv2/core/utils/logger.hpp>
5861

5962
#include "opencv2/core/ocl_genbase.hpp"
@@ -63,6 +66,10 @@
6366
#include "opencv2/core/utils/filesystem.hpp"
6467
#include "opencv2/core/utils/filesystem.private.hpp"
6568

69+
#define CV__ALLOCATOR_STATS_LOG(...) CV_LOG_VERBOSE(NULL, 0, "OpenCL allocator: " << __VA_ARGS__)
70+
#include "opencv2/core/utils/allocator_stats.impl.hpp"
71+
#undef CV__ALLOCATOR_STATS_LOG
72+
6673
#define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0
6774

6875
#define CV_OPENCL_SHOW_RUN_KERNELS 0
@@ -132,6 +139,14 @@ namespace cv { namespace ocl {
132139
void release() { if( CV_XADD(&refcount, -1) == 1 && !cv::__termination) delete this; } \
133140
int refcount
134141

142+
static cv::utils::AllocatorStatistics opencl_allocator_stats;
143+
144+
CV_EXPORTS cv::utils::AllocatorStatisticsInterface& getOpenCLAllocatorStatistics();
145+
cv::utils::AllocatorStatisticsInterface& getOpenCLAllocatorStatistics()
146+
{
147+
return opencl_allocator_stats;
148+
}
149+
135150
#ifndef HAVE_OPENCL
136151
#define CV_OPENCL_NO_SUPPORT() CV_Error(cv::Error::OpenCLApiCallError, "OpenCV build without OpenCL support")
137152
namespace {
@@ -4539,15 +4554,17 @@ class OpenCLAllocator CV_FINAL : public MatAllocator
45394554
mutable OpenCLSVMBufferPoolImpl bufferPoolSVM;
45404555
#endif
45414556

4557+
public:
45424558
enum AllocatorFlags
45434559
{
45444560
ALLOCATOR_FLAGS_BUFFER_POOL_USED = 1 << 0,
4545-
ALLOCATOR_FLAGS_BUFFER_POOL_HOST_PTR_USED = 1 << 1
4561+
ALLOCATOR_FLAGS_BUFFER_POOL_HOST_PTR_USED = 1 << 1,
45464562
#ifdef HAVE_OPENCL_SVM
4547-
,ALLOCATOR_FLAGS_BUFFER_POOL_SVM_USED = 1 << 2
4563+
ALLOCATOR_FLAGS_BUFFER_POOL_SVM_USED = 1 << 2,
45484564
#endif
4565+
ALLOCATOR_FLAGS_EXTERNAL_BUFFER = 1 << 3 // convertFromBuffer()
45494566
};
4550-
public:
4567+
45514568
OpenCLAllocator()
45524569
: bufferPool(0),
45534570
bufferPoolHostPtr(CL_MEM_ALLOC_HOST_PTR)
@@ -4652,6 +4669,7 @@ class OpenCLAllocator CV_FINAL : public MatAllocator
46524669
u->allocatorFlags_ = allocatorFlags;
46534670
CV_DbgAssert(!u->tempUMat()); // for bufferPool.release() consistency in deallocate()
46544671
u->markHostCopyObsolete(true);
4672+
opencl_allocator_stats.onAllocate(u->size);
46554673
return u;
46564674
}
46574675

@@ -4760,6 +4778,7 @@ class OpenCLAllocator CV_FINAL : public MatAllocator
47604778
}
47614779
if(accessFlags & ACCESS_WRITE)
47624780
u->markHostCopyObsolete(true);
4781+
opencl_allocator_stats.onAllocate(u->size);
47634782
return true;
47644783
}
47654784

@@ -4812,6 +4831,13 @@ class OpenCLAllocator CV_FINAL : public MatAllocator
48124831

48134832
void deallocate_(UMatData* u) const
48144833
{
4834+
CV_Assert(u);
4835+
CV_Assert(u->handle);
4836+
if ((u->allocatorFlags_ & ALLOCATOR_FLAGS_EXTERNAL_BUFFER) == 0)
4837+
{
4838+
opencl_allocator_stats.onFree(u->size);
4839+
}
4840+
48154841
#ifdef _WIN32
48164842
if (cv::__termination) // process is not in consistent state (after ExitProcess call) and terminating
48174843
return; // avoid any OpenCL calls
@@ -5793,7 +5819,7 @@ void convertFromBuffer(void* cl_mem_buffer, size_t step, int rows, int cols, int
57935819
// attach clBuffer to UMatData
57945820
dst.u = new UMatData(getOpenCLAllocator());
57955821
dst.u->data = 0;
5796-
dst.u->allocatorFlags_ = 0; // not allocated from any OpenCV buffer pool
5822+
dst.u->allocatorFlags_ = OpenCLAllocator::ALLOCATOR_FLAGS_EXTERNAL_BUFFER; // not allocated from any OpenCV buffer pool
57975823
dst.u->flags = 0;
57985824
dst.u->handle = cl_mem_buffer;
57995825
dst.u->origdata = 0;

modules/core/src/system.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ static bool param_dumpErrors = utils::getConfigurationParameterBool("OPENCV_DUMP
7171
);
7272

7373
void* allocSingletonBuffer(size_t size) { return fastMalloc(size); }
74+
void* allocSingletonNewBuffer(size_t size) { return malloc(size); }
75+
7476

7577
} // namespace cv
7678

0 commit comments

Comments
 (0)