#include <opencv2/core/utils/configuration.private.hpp>
#include <opencv2/core/utils/trace.private.hpp>
+#include <opencv2/core/utils/logger.hpp>
+
namespace cv {
static Mutex* __initialization_mutex = NULL;
// force initialization (single-threaded environment)
Mutex* __initialization_mutex_initializer = &getInitializationMutex();
+static bool param_dumpErrors = utils::getConfigurationParameterBool("OPENCV_DUMP_ERRORS",
+#if defined(_DEBUG) || defined(__ANDROID__) || (defined(__GNUC__) && !defined(__EXCEPTIONS))
+ true
+#else
+ false
+#endif
+);
+
} // namespace cv
+#ifndef CV_ERROR_SET_TERMINATE_HANDLER // build config option
+# if defined(_WIN32)
+# define CV_ERROR_SET_TERMINATE_HANDLER 1
+# endif
+#endif
+#if defined(CV_ERROR_SET_TERMINATE_HANDLER) && !CV_ERROR_SET_TERMINATE_HANDLER
+# undef CV_ERROR_SET_TERMINATE_HANDLER
+#endif
+
#ifdef _MSC_VER
# if _MSC_VER >= 1700
# pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
# endif
#endif
+#ifdef CV_ERROR_SET_TERMINATE_HANDLER
+#include <exception> // std::set_terminate
+#include <cstdlib> // std::abort
+#endif
+
#if defined __ANDROID__ || defined __linux__ || defined __FreeBSD__ || defined __HAIKU__
# include <unistd.h>
# include <fcntl.h>
#undef max
#undef abs
#include <tchar.h>
-#if defined _MSC_VER
- #if _MSC_VER >= 1400
- #include <intrin.h>
- #elif defined _M_IX86
- static void __cpuid(int* cpuid_data, int)
- {
- __asm
- {
- push ebx
- push edi
- mov edi, cpuid_data
- mov eax, 1
- cpuid
- mov [edi], eax
- mov [edi + 4], ebx
- mov [edi + 8], ecx
- mov [edi + 12], edx
- pop edi
- pop ebx
- }
- }
- static void __cpuidex(int* cpuid_data, int, int)
- {
- __asm
- {
- push edi
- mov edi, cpuid_data
- mov eax, 7
- mov ecx, 0
- cpuid
- mov [edi], eax
- mov [edi + 4], ebx
- mov [edi + 8], ecx
- mov [edi + 12], edx
- pop edi
- }
- }
- #endif
-#endif
#ifdef WINRT
#include <wrl/client.h>
# include <android/log.h>
#endif
+#ifdef DECLARE_CV_CPUID_X86
+DECLARE_CV_CPUID_X86
+#endif
+#ifndef CV_CPUID_X86
+ #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
+ #if _MSC_VER >= 1400 // MSVS 2005
+ #include <intrin.h> // __cpuidex()
+ #define CV_CPUID_X86 __cpuidex
+ #else
+ #error "Required MSVS 2005+"
+ #endif
+ #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+ static void cv_cpuid(int* cpuid_data, int reg_eax, int reg_ecx)
+ {
+ int __eax = reg_eax, __ebx = 0, __ecx = reg_ecx, __edx = 0;
+// tested with available compilers (-fPIC -O2 -m32/-m64): https://godbolt.org/
+#if !defined(__PIC__) \
+ || defined(__x86_64__) || __GNUC__ >= 5 \
+ || defined(__clang__) || defined(__INTEL_COMPILER)
+ __asm__("cpuid\n\t"
+ : "+a" (__eax), "=b" (__ebx), "+c" (__ecx), "=d" (__edx)
+ );
+#elif defined(__i386__) // ebx may be reserved as the PIC register
+ __asm__("xchg{l}\t{%%}ebx, %1\n\t"
+ "cpuid\n\t"
+ "xchg{l}\t{%%}ebx, %1\n\t"
+ : "+a" (__eax), "=&r" (__ebx), "+c" (__ecx), "=d" (__edx)
+ );
+#else
+#error "Configuration error"
+#endif
+ cpuid_data[0] = __eax; cpuid_data[1] = __ebx; cpuid_data[2] = __ecx; cpuid_data[3] = __edx;
+ }
+ #define CV_CPUID_X86 cv_cpuid
+ #endif
+#endif
+
+
namespace cv
{
void Exception::formatMessage()
{
- if( func.size() > 0 )
- msg = format("OpenCV(%s) %s:%d: error: (%d) %s in function %s\n", CV_VERSION, file.c_str(), line, code, err.c_str(), func.c_str());
+ size_t pos = err.find('\n');
+ bool multiline = pos != cv::String::npos;
+ if (multiline)
+ {
+ std::stringstream ss;
+ size_t prev_pos = 0;
+ while (pos != cv::String::npos)
+ {
+ ss << "> " << err.substr(prev_pos, pos - prev_pos) << std::endl;
+ prev_pos = pos + 1;
+ pos = err.find('\n', prev_pos);
+ }
+ ss << "> " << err.substr(prev_pos);
+ if (err[err.size() - 1] != '\n')
+ ss << std::endl;
+ err = ss.str();
+ }
+ if (func.size() > 0)
+ {
+ if (multiline)
+ msg = format("OpenCV(%s) %s:%d: error: (%d:%s) in function '%s'\n%s", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), func.c_str(), err.c_str());
+ else
+ msg = format("OpenCV(%s) %s:%d: error: (%d:%s) %s in function '%s'\n", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), err.c_str(), func.c_str());
+ }
else
- msg = format("OpenCV(%s) %s:%d: error: (%d) %s\n", CV_VERSION, file.c_str(), line, code, err.c_str());
+ {
+ msg = format("OpenCV(%s) %s:%d: error: (%d:%s) %s%s", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), err.c_str(), multiline ? "" : "\n");
+ }
}
static const char* g_hwFeatureNames[CV_HARDWARE_MAX_FEATURE] = { NULL };
initializeNames();
+ #ifdef CV_CPUID_X86
int cpuid_data[4] = { 0, 0, 0, 0 };
int cpuid_data_ex[4] = { 0, 0, 0, 0 };
- #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
- #define OPENCV_HAVE_X86_CPUID 1
- __cpuid(cpuid_data, 1);
- #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
- #define OPENCV_HAVE_X86_CPUID 1
- #ifdef __x86_64__
- asm __volatile__
- (
- "movl $1, %%eax\n\t"
- "cpuid\n\t"
- :[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3])
- :
- : "cc"
- );
- #else
- asm volatile
- (
- "pushl %%ebx\n\t"
- "movl $1,%%eax\n\t"
- "cpuid\n\t"
- "popl %%ebx\n\t"
- : "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3])
- :
- : "cc"
- );
- #endif
- #endif
+ CV_CPUID_X86(cpuid_data, 1, 0/*unused*/);
- #ifdef OPENCV_HAVE_X86_CPUID
int x86_family = (cpuid_data[0] >> 8) & 15;
if( x86_family >= 6 )
{
// make the second call to the cpuid command in order to get
// information about extended features like AVX2
- #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
- #define OPENCV_HAVE_X86_CPUID_EX 1
- __cpuidex(cpuid_data_ex, 7, 0);
- #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
- #define OPENCV_HAVE_X86_CPUID_EX 1
- #ifdef __x86_64__
- asm __volatile__
- (
- "movl $7, %%eax\n\t"
- "movl $0, %%ecx\n\t"
- "cpuid\n\t"
- :[eax]"=a"(cpuid_data_ex[0]),[ebx]"=b"(cpuid_data_ex[1]),[ecx]"=c"(cpuid_data_ex[2]),[edx]"=d"(cpuid_data_ex[3])
- :
- : "cc"
- );
- #else
- asm volatile
- (
- "pushl %%ebx\n\t"
- "movl $7,%%eax\n\t"
- "movl $0,%%ecx\n\t"
- "cpuid\n\t"
- "movl %%ebx, %0\n\t"
- "popl %%ebx\n\t"
- : "=r"(cpuid_data_ex[1]), "=c"(cpuid_data_ex[2])
- :
- : "cc"
- );
- #endif
- #endif
+ CV_CPUID_X86(cpuid_data_ex, 7, 0);
- #ifdef OPENCV_HAVE_X86_CPUID_EX
have[CV_CPU_AVX2] = (cpuid_data_ex[1] & (1<<5)) != 0;
have[CV_CPU_AVX_512F] = (cpuid_data_ex[1] & (1<<16)) != 0;
have[CV_CPU_AVX_512BW] = (cpuid_data_ex[1] & (1<<30)) != 0;
have[CV_CPU_AVX_512VL] = (cpuid_data_ex[1] & (1<<31)) != 0;
have[CV_CPU_AVX_512VBMI] = (cpuid_data_ex[2] & (1<<1)) != 0;
- #else
- CV_UNUSED(cpuid_data_ex);
- #endif
bool have_AVX_OS_support = true;
bool have_AVX512_OS_support = true;
#ifdef _XCR_XFEATURE_ENABLED_MASK // requires immintrin.h
xcr0 = (int)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
- __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
+ __asm__ ("xgetbv\n\t" : "=a" (xcr0) : "c" (0) : "%edx" );
#endif
if ((xcr0 & 0x6) != 0x6)
have_AVX_OS_support = false; // YMM registers
have[CV_CPU_AVX512_SKX] = have[CV_CPU_AVX_512F] & have[CV_CPU_AVX_512CD] & have[CV_CPU_AVX_512BW] & have[CV_CPU_AVX_512DQ] & have[CV_CPU_AVX_512VL];
}
}
- #else
- CV_UNUSED(cpuid_data);
- CV_UNUSED(cpuid_data_ex);
- #endif // OPENCV_HAVE_X86_CPUID
+ #endif // CV_CPUID_X86
#if defined __ANDROID__ || defined __linux__
#ifdef __aarch64__
have[CV_CPU_FP16] = true;
#elif defined __arm__ && defined __ANDROID__
#if defined HAVE_CPUFEATURES
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "calling android_getCpuFeatures() ...");
+ CV_LOG_INFO(NULL, "calling android_getCpuFeatures() ...");
uint64_t features = android_getCpuFeatures();
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "calling android_getCpuFeatures() ... Done (%llx)", features);
+ CV_LOG_INFO(NULL, cv::format("calling android_getCpuFeatures() ... Done (%llx)", (long long)features));
have[CV_CPU_NEON] = (features & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
have[CV_CPU_FP16] = (features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) != 0;
#else
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "cpufeatures library is not available for CPU detection");
+ CV_LOG_INFO(NULL, "cpufeatures library is not available for CPU detection");
#if CV_NEON
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "- NEON instructions is enabled via build flags");
+ CV_LOG_INFO(NULL, "- NEON instructions is enabled via build flags");
have[CV_CPU_NEON] = true;
#else
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "- NEON instructions is NOT enabled via build flags");
+ CV_LOG_INFO(NULL, "- NEON instructions is NOT enabled via build flags");
#endif
#if CV_FP16
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "- FP16 instructions is enabled via build flags");
+ CV_LOG_INFO(NULL, "- FP16 instructions is enabled via build flags");
have[CV_CPU_FP16] = true;
#else
- __android_log_print(ANDROID_LOG_INFO, "OpenCV", "- FP16 instructions is NOT enabled via build flags");
+ CV_LOG_INFO(NULL, "- FP16 instructions is NOT enabled via build flags");
#endif
#endif
#elif defined __arm__
"******************************************************************\n");
fprintf(stderr, "\nRequired baseline features:\n");
checkFeatures(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]), true);
- CV_ErrorNoReturn(cv::Error::StsAssert, "Missing support for required CPU baseline features. Check OpenCV build configuration and required CPU/HW setup.");
+ CV_Error(cv::Error::StsAssert, "Missing support for required CPU baseline features. Check OpenCV build configuration and required CPU/HW setup.");
}
readSettings(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]));
static inline bool isSymbolSeparator(char c)
{
- return c == ',' || c == ';' || c == '-';
+ return c == ',' || c == ';';
}
void readSettings(const int* baseline_features, int baseline_count)
return name ? String(name) : String();
}
+std::string getCPUFeaturesLine()
+{
+ const int features[] = { CV_CPU_BASELINE_FEATURES, CV_CPU_DISPATCH_FEATURES };
+ const int sz = sizeof(features) / sizeof(features[0]);
+ std::string result;
+ std::string prefix;
+ for (int i = 1; i < sz; ++i)
+ {
+ if (features[i] == 0)
+ {
+ prefix = "*";
+ continue;
+ }
+ if (i != 1) result.append(" ");
+ result.append(prefix);
+ result.append(getHWFeatureNameSafe(features[i]));
+ if (!checkHardwareSupport(features[i])) result.append("?");
+ }
+ return result;
+}
+
volatile bool useOptimizedFlag = true;
void setUseOptimized( bool flag )
int64 getCPUTickCount(void)
{
- int64 result = 0;
unsigned upper, lower, tmp;
__asm__ volatile(
"0: \n"
return build_info;
}
+String getVersionString() { return String(CV_VERSION); }
+
+int getVersionMajor() { return CV_VERSION_MAJOR; }
+
+int getVersionMinor() { return CV_VERSION_MINOR; }
+
+int getVersionRevision() { return CV_VERSION_REVISION; }
+
String format( const char* fmt, ... )
{
AutoBuffer<char, 1024> buf;
va_list va;
va_start(va, fmt);
int bsize = static_cast<int>(buf.size());
- int len = cv_vsnprintf((char *)buf, bsize, fmt, va);
+ int len = cv_vsnprintf(buf.data(), bsize, fmt, va);
va_end(va);
CV_Assert(len >= 0 && "Check format string for errors");
continue;
}
buf[bsize - 1] = 0;
- return String((char *)buf, len);
+ return String(buf.data(), len);
}
}
#endif
}
+static void dumpException(const Exception& exc)
+{
+ const char* errorStr = cvErrorStr(exc.code);
+ char buf[1 << 12];
+
+ cv_snprintf(buf, sizeof(buf),
+ "OpenCV(%s) Error: %s (%s) in %s, file %s, line %d",
+ CV_VERSION,
+ errorStr, exc.err.c_str(), exc.func.size() > 0 ?
+ exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line);
+#ifdef __ANDROID__
+ __android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf);
+#else
+ fflush(stdout); fflush(stderr);
+ fprintf(stderr, "%s\n", buf);
+ fflush(stderr);
+#endif
+}
+
+#ifdef CV_ERROR_SET_TERMINATE_HANDLER
+static bool cv_terminate_handler_installed = false;
+static std::terminate_handler cv_old_terminate_handler;
+static cv::Exception cv_terminate_handler_exception;
+static bool param_setupTerminateHandler = utils::getConfigurationParameterBool("OPENCV_SETUP_TERMINATE_HANDLER", true);
+static void cv_terminate_handler() {
+ std::cerr << "OpenCV: terminate handler is called! The last OpenCV error is:\n";
+ dumpException(cv_terminate_handler_exception);
+ if (false /*cv_old_terminate_handler*/) // buggy behavior is observed with doubled "abort/retry/ignore" windows
+ cv_old_terminate_handler();
+ abort();
+}
+
+#endif
+
void error( const Exception& exc )
{
+#ifdef CV_ERROR_SET_TERMINATE_HANDLER
+ {
+ cv::AutoLock lock(getInitializationMutex());
+ if (!cv_terminate_handler_installed)
+ {
+ if (param_setupTerminateHandler)
+ cv_old_terminate_handler = std::set_terminate(cv_terminate_handler);
+ cv_terminate_handler_installed = true;
+ }
+ cv_terminate_handler_exception = exc;
+ }
+#endif
+
if (customErrorCallback != 0)
customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(),
exc.file.c_str(), exc.line, customErrorCallbackData);
- else
+ else if (param_dumpErrors)
{
- const char* errorStr = cvErrorStr(exc.code);
- char buf[1 << 12];
-
- cv_snprintf(buf, sizeof(buf),
- "OpenCV(%s) Error: %s (%s) in %s, file %s, line %d",
- CV_VERSION,
- errorStr, exc.err.c_str(), exc.func.size() > 0 ?
- exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line);
- fprintf( stderr, "%s\n", buf );
- fflush( stderr );
-# ifdef __ANDROID__
- __android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf);
-# endif
+ dumpException(exc);
}
if(breakOnError)
{
return false;
}
- CV_ErrorNoReturn(cv::Error::StsBadArg, cv::format("Invalid value for %s parameter: %s", name, value.c_str()));
+ CV_Error(cv::Error::StsBadArg, cv::format("Invalid value for %s parameter: %s", name, value.c_str()));
}
return v * 1024 * 1024;
else if (suffixStr == "KB" || suffixStr == "Kb" || suffixStr == "kb")
return v * 1024;
- CV_ErrorNoReturn(cv::Error::StsBadArg, cv::format("Invalid value for %s parameter: %s", name, value.c_str()));
+ CV_Error(cv::Error::StsBadArg, cv::format("Invalid value for %s parameter: %s", name, value.c_str()));
}
cv::String utils::getConfigurationParameterString(const char* name, const char* defaultValue)