diff --git a/cmake/OpenCVDetectCXXCompiler.cmake b/cmake/OpenCVDetectCXXCompiler.cmake index c27fb4f549..f9fc1189ce 100644 --- a/cmake/OpenCVDetectCXXCompiler.cmake +++ b/cmake/OpenCVDetectCXXCompiler.cmake @@ -212,7 +212,13 @@ if(NOT HAVE_CXX11) endif() endif() -if((HAVE_CXX11 +set(__OPENCV_ENABLE_ATOMIC_LONG_LONG OFF) +if(HAVE_CXX11 AND (X86 OR X86_64)) + set(__OPENCV_ENABLE_ATOMIC_LONG_LONG ON) +endif() +option(OPENCV_ENABLE_ATOMIC_LONG_LONG "Enable C++ compiler support for atomic" ${__OPENCV_ENABLE_ATOMIC_LONG_LONG}) + +if((HAVE_CXX11 AND OPENCV_ENABLE_ATOMIC_LONG_LONG AND NOT MSVC AND NOT (X86 OR X86_64) AND NOT OPENCV_SKIP_LIBATOMIC_COMPILER_CHECK) @@ -223,9 +229,14 @@ if((HAVE_CXX11 list(APPEND CMAKE_REQUIRED_LIBRARIES atomic) ocv_check_compiler_flag(CXX "" HAVE_CXX_ATOMICS_WITH_LIB "${OpenCV_SOURCE_DIR}/cmake/checks/atomic_check.cpp") if(HAVE_CXX_ATOMICS_WITH_LIB) + set(HAVE_ATOMIC_LONG_LONG ON) list(APPEND OPENCV_LINKER_LIBS atomic) else() - message(FATAL_ERROR "C++11 compiler must support std::atomic") + message(STATUS "Compiler doesn't support std::atomic") endif() + else() + set(HAVE_ATOMIC_LONG_LONG ON) endif() +else(HAVE_CXX11 AND OPENCV_ENABLE_ATOMIC_LONG_LONG) + set(HAVE_ATOMIC_LONG_LONG ${OPENCV_ENABLE_ATOMIC_LONG_LONG}) endif() diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 2e0fac6172..4cb61a1d82 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -78,6 +78,23 @@ if(HAVE_MEMALIGN) ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/alloc.cpp "HAVE_MEMALIGN=1") endif() +option(OPENCV_ENABLE_ALLOCATOR_STATS "Enable Allocator metrics" ON) + +if(NOT OPENCV_ENABLE_ALLOCATOR_STATS) + add_definitions(-DOPENCV_DISABLE_ALLOCATOR_STATS=1) +else() + if(NOT DEFINED OPENCV_ALLOCATOR_STATS_COUNTER_TYPE) + if(HAVE_ATOMIC_LONG_LONG AND OPENCV_ENABLE_ATOMIC_LONG_LONG) + set(OPENCV_ALLOCATOR_STATS_COUNTER_TYPE "long long") + else() + set(OPENCV_ALLOCATOR_STATS_COUNTER_TYPE "int") + endif() + endif() + message(STATUS "Allocator metrics storage type: '${OPENCV_ALLOCATOR_STATS_COUNTER_TYPE}'") + add_definitions("-DOPENCV_ALLOCATOR_STATS_COUNTER_TYPE=${OPENCV_ALLOCATOR_STATS_COUNTER_TYPE}") +endif() + + ocv_create_module(${extra_libs}) ocv_target_link_libraries(${the_module} PRIVATE diff --git a/modules/core/include/opencv2/core/utils/allocator_stats.impl.hpp b/modules/core/include/opencv2/core/utils/allocator_stats.impl.hpp index b77493d010..61fcf15977 100644 --- a/modules/core/include/opencv2/core/utils/allocator_stats.impl.hpp +++ b/modules/core/include/opencv2/core/utils/allocator_stats.impl.hpp @@ -11,32 +11,55 @@ #include #endif +//#define OPENCV_DISABLE_ALLOCATOR_STATS + namespace cv { namespace utils { +#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE +#if defined(__GNUC__) && (\ + (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4) || \ + (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \ + ) +#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE int +#endif +#endif + +#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE +#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE long long +#endif + #ifdef CV__ALLOCATOR_STATS_LOG namespace { #endif class AllocatorStatistics : public AllocatorStatisticsInterface { -protected: -#ifdef CV_CXX11 - std::atomic curr, total, total_allocs, peak; -#else - volatile long long curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only -#endif +#ifdef OPENCV_DISABLE_ALLOCATOR_STATS public: - AllocatorStatistics() -#ifndef CV_CXX11 - : curr(0), total(0), total_allocs(0), peak(0) -#endif - {} + AllocatorStatistics() {} ~AllocatorStatistics() CV_OVERRIDE {} - // AllocatorStatisticsInterface + uint64_t getCurrentUsage() const CV_OVERRIDE { return 0; } + uint64_t getTotalUsage() const CV_OVERRIDE { return 0; } + uint64_t getNumberOfAllocations() const CV_OVERRIDE { return 0; } + uint64_t getPeakUsage() const CV_OVERRIDE { return 0; } + + /** set peak usage = current usage */ + void resetPeakUsage() CV_OVERRIDE {}; + + void onAllocate(size_t /*sz*/) {} + void onFree(size_t /*sz*/) {} + +#elif defined(CV_CXX11) + +protected: + typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t; + std::atomic curr, total, total_allocs, peak; +public: + AllocatorStatistics() {} + ~AllocatorStatistics() CV_OVERRIDE {} -#ifdef CV_CXX11 uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr.load(); } uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total.load(); } uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs.load(); } @@ -52,7 +75,7 @@ public: CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); #endif - long long new_curr = curr.fetch_add((long long)sz) + (long long)sz; + counter_t new_curr = curr.fetch_add((counter_t)sz) + (counter_t)sz; // peak = std::max((uint64_t)peak, new_curr); auto prev_peak = peak.load(); @@ -63,7 +86,7 @@ public: } // end of peak = max(...) - total += (long long)sz; + total += (counter_t)sz; total_allocs++; } void onFree(size_t sz) @@ -71,10 +94,20 @@ public: #ifdef CV__ALLOCATOR_STATS_LOG CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); #endif - curr -= (long long)sz; + curr -= (counter_t)sz; } -#else +#else // non C++11 + +protected: + typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t; + volatile counter_t curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only +public: + AllocatorStatistics() + : curr(0), total(0), total_allocs(0), peak(0) + {} + ~AllocatorStatistics() CV_OVERRIDE {} + uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr; } uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total; } uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs; } @@ -89,21 +122,21 @@ public: CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); #endif - uint64_t new_curr = (uint64_t)CV_XADD(&curr, (uint64_t)sz) + sz; + counter_t new_curr = (counter_t)CV_XADD(&curr, (counter_t)sz) + (counter_t)sz; - peak = std::max((uint64_t)peak, new_curr); // non-thread safe + peak = std::max((counter_t)peak, new_curr); // non-thread safe //CV_XADD(&total, (uint64_t)sz); // overflow with int, non-reliable... total += sz; - CV_XADD(&total_allocs, (uint64_t)1); + CV_XADD(&total_allocs, (counter_t)1); } void onFree(size_t sz) { #ifdef CV__ALLOCATOR_STATS_LOG CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); #endif - CV_XADD(&curr, (uint64_t)-sz); + CV_XADD(&curr, (counter_t)-sz); } #endif };