opencv/modules/core/src/trace.cpp

1147 lines
34 KiB
C++
Raw Normal View History

2017-05-25 23:59:01 +08:00
// 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 "precomp.hpp"
2017-05-25 23:59:01 +08:00
#include <opencv2/core/utils/trace.hpp>
#include <opencv2/core/utils/trace.private.hpp>
Merge pull request #9114 from pengli:dnn_rebase add libdnn acceleration to dnn module (#9114) * import libdnn code Signed-off-by: Li Peng <peng.li@intel.com> * add convolution layer ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * add pooling layer ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * add softmax layer ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * add lrn layer ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * add innerproduct layer ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * add HAVE_OPENCL macro Signed-off-by: Li Peng <peng.li@intel.com> * fix for convolution ocl Signed-off-by: Li Peng <peng.li@intel.com> * enable getUMat() for multi-dimension Mat Signed-off-by: Li Peng <peng.li@intel.com> * use getUMat for ocl acceleration Signed-off-by: Li Peng <peng.li@intel.com> * use CV_OCL_RUN macro Signed-off-by: Li Peng <peng.li@intel.com> * set OPENCL target when it is available and disable fuseLayer for OCL target for the time being Signed-off-by: Li Peng <peng.li@intel.com> * fix innerproduct accuracy test Signed-off-by: Li Peng <peng.li@intel.com> * remove trailing space Signed-off-by: Li Peng <peng.li@intel.com> * Fixed tensorflow demo bug. Root cause is that tensorflow has different algorithm with libdnn to calculate convolution output dimension. libdnn don't calculate output dimension anymore and just use one passed in by config. * split gemm ocl file split it into gemm_buffer.cl and gemm_image.cl Signed-off-by: Li Peng <peng.li@intel.com> * Fix compile failure Signed-off-by: Li Peng <peng.li@intel.com> * check env flag for auto tuning Signed-off-by: Li Peng <peng.li@intel.com> * switch to new ocl kernels for softmax layer Signed-off-by: Li Peng <peng.li@intel.com> * update softmax layer on some platform subgroup extension may not work well, fallback to non subgroup ocl acceleration. Signed-off-by: Li Peng <peng.li@intel.com> * fallback to cpu path for fc layer with multi output Signed-off-by: Li Peng <peng.li@intel.com> * update output message Signed-off-by: Li Peng <peng.li@intel.com> * update fully connected layer fallback to gemm API if libdnn return false Signed-off-by: Li Peng <peng.li@intel.com> * Add ReLU OCL implementation * disable layer fusion for now Signed-off-by: Li Peng <peng.li@intel.com> * Add OCL implementation for concat layer Signed-off-by: Wu Zhiwen <zhiwen.wu@intel.com> * libdnn: update license and copyrights Also refine libdnn coding style Signed-off-by: Wu Zhiwen <zhiwen.wu@intel.com> Signed-off-by: Li Peng <peng.li@intel.com> * DNN: Don't link OpenCL library explicitly * DNN: Make default preferableTarget to DNN_TARGET_CPU User should set it to DNN_TARGET_OPENCL explicitly if want to use OpenCL acceleration. Also don't fusion when using DNN_TARGET_OPENCL * DNN: refine coding style * Add getOpenCLErrorString * DNN: Use int32_t/uint32_t instread of alias * Use namespace ocl4dnn to include libdnn things * remove extra copyTo in softmax ocl path Signed-off-by: Li Peng <peng.li@intel.com> * update ReLU layer ocl path Signed-off-by: Li Peng <peng.li@intel.com> * Add prefer target property for layer class It is used to indicate the target for layer forwarding, either the default CPU target or OCL target. Signed-off-by: Li Peng <peng.li@intel.com> * Add cl_event based timer for cv::ocl * Rename libdnn to ocl4dnn Signed-off-by: Li Peng <peng.li@intel.com> Signed-off-by: wzw <zhiwen.wu@intel.com> * use UMat for ocl4dnn internal buffer Remove allocateMemory which use clCreateBuffer directly Signed-off-by: Li Peng <peng.li@intel.com> Signed-off-by: wzw <zhiwen.wu@intel.com> * enable buffer gemm in ocl4dnn innerproduct Signed-off-by: Li Peng <peng.li@intel.com> * replace int_tp globally for ocl4dnn kernels. Signed-off-by: wzw <zhiwen.wu@intel.com> Signed-off-by: Li Peng <peng.li@intel.com> * create UMat for layer params Signed-off-by: Li Peng <peng.li@intel.com> * update sign ocl kernel Signed-off-by: Li Peng <peng.li@intel.com> * update image based gemm of inner product layer Signed-off-by: Li Peng <peng.li@intel.com> * remove buffer gemm of inner product layer call cv::gemm API instead Signed-off-by: Li Peng <peng.li@intel.com> * change ocl4dnn forward parameter to UMat Signed-off-by: Li Peng <peng.li@intel.com> * Refine auto-tuning mechanism. - Use OPENCV_OCL4DNN_KERNEL_CONFIG_PATH to set cache directory for fine-tuned kernel configuration. e.g. export OPENCV_OCL4DNN_KERNEL_CONFIG_PATH=/home/tmp, the cache directory will be /home/tmp/spatialkernels/ on Linux. - Define environment OPENCV_OCL4DNN_ENABLE_AUTO_TUNING to enable auto-tuning. - OPENCV_OPENCL_ENABLE_PROFILING is only used to enable profiling for OpenCL command queue. This fix basic kernel get wrong running time, i.e. 0ms. - If creating cache directory failed, disable auto-tuning. * Detect and create cache dir on windows Signed-off-by: Li Peng <peng.li@intel.com> * Refine gemm like convolution kernel. Signed-off-by: Li Peng <peng.li@intel.com> * Fix redundant swizzleWeights calling when use cached kernel config. * Fix "out of resource" bug when auto-tuning too many kernels. * replace cl_mem with UMat in ocl4dnnConvSpatial class * OCL4DNN: reduce the tuning kernel candidate. This patch could reduce 75% of the tuning candidates with less than 2% performance impact for the final result. Signed-off-by: Zhigang Gong <zhigang.gong@intel.com> * replace cl_mem with umat in ocl4dnn convolution Signed-off-by: Li Peng <peng.li@intel.com> * remove weight_image_ of ocl4dnn inner product Actually it is unused in the computation Signed-off-by: Li Peng <peng.li@intel.com> * Various fixes for ocl4dnn 1. OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()) 2. Ptr<OCL4DNNInnerProduct<float> > innerProductOp 3. Code comments cleanup 4. ignore check on OCL cpu device Signed-off-by: Li Peng <peng.li@intel.com> * add build option for log softmax Signed-off-by: Li Peng <peng.li@intel.com> * remove unused ocl kernels in ocl4dnn Signed-off-by: Li Peng <peng.li@intel.com> * replace ocl4dnnSet with opencv setTo Signed-off-by: Li Peng <peng.li@intel.com> * replace ALIGN with cv::alignSize Signed-off-by: Li Peng <peng.li@intel.com> * check kernel build options Signed-off-by: Li Peng <peng.li@intel.com> * Handle program compilation fail properly. * Use std::numeric_limits<float>::infinity() for large float number * check ocl4dnn kernel compilation result Signed-off-by: Li Peng <peng.li@intel.com> * remove unused ctx_id Signed-off-by: Li Peng <peng.li@intel.com> * change clEnqueueNDRangeKernel to kernel.run() Signed-off-by: Li Peng <peng.li@intel.com> * change cl_mem to UMat in image based gemm Signed-off-by: Li Peng <peng.li@intel.com> * check intel subgroup support for lrn and pooling layer Signed-off-by: Li Peng <peng.li@intel.com> * Fix convolution bug if group is greater than 1 Signed-off-by: Li Peng <peng.li@intel.com> * Set default layer preferableTarget to be DNN_TARGET_CPU Signed-off-by: Li Peng <peng.li@intel.com> * Add ocl perf test for convolution Signed-off-by: Li Peng <peng.li@intel.com> * Add more ocl accuracy test Signed-off-by: Li Peng <peng.li@intel.com> * replace cl_image with ocl::Image2D Signed-off-by: Li Peng <peng.li@intel.com> * Fix build failure in elementwise layer Signed-off-by: Li Peng <peng.li@intel.com> * use getUMat() to get blob data Signed-off-by: Li Peng <peng.li@intel.com> * replace cl_mem handle with ocl::KernelArg Signed-off-by: Li Peng <peng.li@intel.com> * dnn(build): don't use C++11, OPENCL_LIBRARIES fix * dnn(ocl4dnn): remove unused OpenCL kernels * dnn(ocl4dnn): extract OpenCL code into .cl files * dnn(ocl4dnn): refine auto-tuning Defaultly disable auto-tuning, set OPENCV_OCL4DNN_ENABLE_AUTO_TUNING environment variable to enable it. Use a set of pre-tuned configs as default config if auto-tuning is disabled. These configs are tuned for Intel GPU with 48/72 EUs, and for googlenet, AlexNet, ResNet-50 If default config is not suitable, use the first available kernel config from the candidates. Candidate priority from high to low is gemm like kernel, IDLF kernel, basick kernel. * dnn(ocl4dnn): pooling doesn't use OpenCL subgroups * dnn(ocl4dnn): fix perf test OpenCV has default 3sec time limit for each performance test. Warmup OpenCL backend outside of perf measurement loop. * use ocl::KernelArg as much as possible Signed-off-by: Li Peng <peng.li@intel.com> * dnn(ocl4dnn): fix bias bug for gemm like kernel * dnn(ocl4dnn): wrap cl_mem into UMat Signed-off-by: Li Peng <peng.li@intel.com> * dnn(ocl4dnn): Refine signature of kernel config - Use more readable string as signture of kernel config - Don't count device name and vendor in signature string - Default kernel configurations are tuned for Intel GPU with 24/48/72 EUs, and for googlenet, AlexNet, ResNet-50 net model. * dnn(ocl4dnn): swap width/height in configuration * dnn(ocl4dnn): enable configs for Intel OpenCL runtime only * core: make configuration helper functions accessible from non-core modules * dnn(ocl4dnn): update kernel auto-tuning behavior Avoid unwanted creation of directories * dnn(ocl4dnn): simplify kernel to workaround OpenCL compiler crash * dnn(ocl4dnn): remove redundant code * dnn(ocl4dnn): Add more clear message for simd size dismatch. * dnn(ocl4dnn): add const to const argument Signed-off-by: Li Peng <peng.li@intel.com> * dnn(ocl4dnn): force compiler use a specific SIMD size for IDLF kernel * dnn(ocl4dnn): drop unused tuneLocalSize() * dnn(ocl4dnn): specify OpenCL queue for Timer and convolve() method * dnn(ocl4dnn): sanitize file names used for cache * dnn(perf): enable Network tests with OpenCL * dnn(ocl4dnn/conv): drop computeGlobalSize() * dnn(ocl4dnn/conv): drop unused fields * dnn(ocl4dnn/conv): simplify ctor * dnn(ocl4dnn/conv): refactor kernelConfig localSize=NULL * dnn(ocl4dnn/conv): drop unsupported double / untested half types * dnn(ocl4dnn/conv): drop unused variable * dnn(ocl4dnn/conv): alignSize/divUp * dnn(ocl4dnn/conv): use enum values * dnn(ocl4dnn): drop unused innerproduct variable Signed-off-by: Li Peng <peng.li@intel.com> * dnn(ocl4dnn): add an generic function to check cl option support * dnn(ocl4dnn): run softmax subgroup version kernel first Signed-off-by: Li Peng <peng.li@intel.com>
2017-10-02 20:38:00 +08:00
#include <opencv2/core/utils/configuration.private.hpp>
2017-05-25 23:59:01 +08:00
#include <opencv2/core/opencl/ocl_defs.hpp>
2017-05-25 23:59:01 +08:00
#include <cstdarg> // va_start
#include <sstream>
#include <ostream>
#include <fstream>
#if 0
#define CV_LOG(...) CV_LOG_INFO(NULL, __VA_ARGS__)
#else
#define CV_LOG(...) {}
#endif
#if 0
#define CV_LOG_ITT(...) CV_LOG_INFO(NULL, __VA_ARGS__)
#else
#define CV_LOG_ITT(...) {}
#endif
#if 1
#define CV_LOG_TRACE_BAILOUT(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
#else
#define CV_LOG_TRACE_BAILOUT(...) {}
#endif
#if 0
#define CV_LOG_PARALLEL(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
#else
#define CV_LOG_PARALLEL(...) {}
#endif
#if 0
#define CV_LOG_CTX_STAT(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
#else
#define CV_LOG_CTX_STAT(...) {}
#endif
#if 0
#define CV_LOG_SKIP(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
#else
#define CV_LOG_SKIP(...) {}
#endif
namespace cv {
namespace utils {
namespace trace {
namespace details {
#ifdef OPENCV_TRACE
2017-06-27 13:16:40 +08:00
#ifdef _MSC_VER
#pragma warning(disable:4065) // switch statement contains 'default' but no 'case' labels
#endif
static bool getParameterTraceEnable()
{
static bool param_traceEnable = utils::getConfigurationParameterBool("OPENCV_TRACE", false);
return param_traceEnable;
}
2017-05-25 23:59:01 +08:00
// TODO lazy configuration flags
2017-05-25 23:59:01 +08:00
static int param_maxRegionDepthOpenCV = (int)utils::getConfigurationParameterSizeT("OPENCV_TRACE_DEPTH_OPENCV", 1);
static int param_maxRegionChildrenOpenCV = (int)utils::getConfigurationParameterSizeT("OPENCV_TRACE_MAX_CHILDREN_OPENCV", 1000);
static int param_maxRegionChildren = (int)utils::getConfigurationParameterSizeT("OPENCV_TRACE_MAX_CHILDREN", 10000);
static const cv::String& getParameterTraceLocation()
{
static cv::String param_traceLocation = utils::getConfigurationParameterString("OPENCV_TRACE_LOCATION", "OpenCVTrace");
return param_traceLocation;
}
2017-05-25 23:59:01 +08:00
#ifdef HAVE_OPENCL
static bool param_synchronizeOpenCL = utils::getConfigurationParameterBool("OPENCV_TRACE_SYNC_OPENCL", false);
#endif
#ifdef OPENCV_WITH_ITT
static bool param_ITT_registerParentScope = utils::getConfigurationParameterBool("OPENCV_TRACE_ITT_PARENT", false);
#endif
static const char* _spaces(int count)
{
static const char buf[64] =
" ";
return &buf[63 - (count & 63)];
}
/**
* Text-based trace messages
*/
class TraceMessage
{
public:
char buffer[1024];
size_t len;
bool hasError;
TraceMessage() :
len(0),
hasError(false)
{}
bool printf(const char* format, ...)
{
char* buf = &buffer[len];
size_t sz = sizeof(buffer) - len;
va_list ap;
va_start(ap, format);
int n = cv_vsnprintf(buf, (int)sz, format, ap);
va_end(ap);
if (n < 0 || (size_t)n > sz)
{
hasError = true;
return false;
}
len += n;
return true;
}
bool formatlocation(const Region::LocationStaticStorage& location)
{
return this->printf("l,%lld,\"%s\",%d,\"%s\",0x%llX\n",
(long long int)(*location.ppExtra)->global_location_id,
location.filename,
location.line,
location.name,
(long long int)(location.flags & ~0xF0000000));
}
bool formatRegionEnter(const Region& region)
{
bool ok = this->printf("b,%d,%lld,%lld,%lld",
(int)region.pImpl->threadID,
(long long int)region.pImpl->beginTimestamp,
(long long int)((*region.pImpl->location.ppExtra)->global_location_id),
(long long int)region.pImpl->global_region_id);
if (region.pImpl->parentRegion && region.pImpl->parentRegion->pImpl)
{
if (region.pImpl->parentRegion->pImpl->threadID != region.pImpl->threadID)
ok &= this->printf(",parentThread=%d,parent=%lld",
(int)region.pImpl->parentRegion->pImpl->threadID,
(long long int)region.pImpl->parentRegion->pImpl->global_region_id);
}
ok &= this->printf("\n");
return ok;
}
bool formatRegionLeave(const Region& region, const RegionStatistics& result)
{
CV_DbgAssert(region.pImpl->endTimestamp - region.pImpl->beginTimestamp == result.duration);
bool ok = this->printf("e,%d,%lld,%lld,%lld,%lld",
(int)region.pImpl->threadID,
(long long int)region.pImpl->endTimestamp,
(long long int)(*region.pImpl->location.ppExtra)->global_location_id,
(long long int)region.pImpl->global_region_id,
(long long int)result.duration);
if (result.currentSkippedRegions)
ok &= this->printf(",skip=%d", (int)result.currentSkippedRegions);
#ifdef HAVE_IPP
if (result.durationImplIPP)
ok &= this->printf(",tIPP=%lld", (long long int)result.durationImplIPP);
#endif
#ifdef HAVE_OPENCL
if (result.durationImplOpenCL)
ok &= this->printf(",tOCL=%lld", (long long int)result.durationImplOpenCL);
#endif
#ifdef HAVE_OPENVX
if (result.durationImplOpenVX)
2017-06-27 01:19:18 +08:00
ok &= this->printf(",tOVX=%lld", (long long int)result.durationImplOpenVX);
2017-05-25 23:59:01 +08:00
#endif
ok &= this->printf("\n");
return ok;
}
bool recordRegionArg(const Region& region, const TraceArg& arg, const char* value)
{
return this->printf("a,%d,%lld,%lld,\"%s\",\"%s\"\n",
region.pImpl->threadID,
(long long int)region.pImpl->beginTimestamp,
(long long int)region.pImpl->global_region_id,
arg.name,
value);
}
};
#ifdef OPENCV_WITH_ITT
static __itt_domain* domain = NULL;
static bool isITTEnabled()
{
static volatile bool isInitialized = false;
2017-05-25 23:59:01 +08:00
static bool isEnabled = false;
if (!isInitialized)
{
cv::AutoLock lock(cv::getInitializationMutex());
if (!isInitialized)
{
bool param_traceITTEnable = utils::getConfigurationParameterBool("OPENCV_TRACE_ITT_ENABLE", true);
if (param_traceITTEnable)
{
isEnabled = !!(__itt_api_version());
CV_LOG_ITT("ITT is " << (isEnabled ? "enabled" : "disabled"));
domain = __itt_domain_create("OpenCVTrace");
}
else
{
CV_LOG_ITT("ITT is disabled through OpenCV parameter");
isEnabled = false;
}
isInitialized = true;
}
2017-05-25 23:59:01 +08:00
}
return isEnabled;
}
#endif
Region::LocationExtraData::LocationExtraData(const LocationStaticStorage& location)
{
CV_UNUSED(location);
static int g_location_id_counter = 0;
global_location_id = CV_XADD(&g_location_id_counter, 1) + 1;
CV_LOG("Register location: " << global_location_id << " (" << (void*)&location << ")"
<< std::endl << " file: " << location.filename
<< std::endl << " line: " << location.line
<< std::endl << " name: " << location.name);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
// Caching is not required here, because there is builtin cache.
// https://software.intel.com/en-us/node/544203:
// Consecutive calls to __itt_string_handle_create with the same name return the same value.
ittHandle_name = __itt_string_handle_create(location.name);
ittHandle_filename = __itt_string_handle_create(location.filename);
}
else
{
ittHandle_name = 0;
ittHandle_filename = 0;
}
2017-05-25 23:59:01 +08:00
#endif
}
/*static*/ Region::LocationExtraData* Region::LocationExtraData::init(const Region::LocationStaticStorage& location)
{
LocationExtraData** pLocationExtra = location.ppExtra;
CV_DbgAssert(pLocationExtra);
if (*pLocationExtra == NULL)
{
cv::AutoLock lock(cv::getInitializationMutex());
if (*pLocationExtra == NULL)
{
*pLocationExtra = new Region::LocationExtraData(location);
TraceStorage* s = getTraceManager().trace_storage.get();
if (s)
{
TraceMessage msg;
msg.formatlocation(location);
s->put(msg);
}
}
}
return *pLocationExtra;
}
Region::Impl::Impl(TraceManagerThreadLocal& ctx, Region* parentRegion_, Region& region_, const LocationStaticStorage& location_, int64 beginTimestamp_) :
location(location_),
region(region_),
parentRegion(parentRegion_),
threadID(ctx.threadID),
global_region_id(++ctx.region_counter),
beginTimestamp(beginTimestamp_),
endTimestamp(0),
directChildrenCount(0)
#ifdef OPENCV_WITH_ITT
,itt_id_registered(false)
,itt_id(__itt_null)
#endif
{
CV_DbgAssert(ctx.currentActiveRegion == parentRegion);
region.pImpl = this;
registerRegion(ctx);
enterRegion(ctx);
}
Region::Impl::~Impl()
{
#ifdef OPENCV_WITH_ITT
if (itt_id_registered)
{
CV_LOG_ITT(" Destroy ITT region: I=" << (void*)this);
__itt_id_destroy(domain, itt_id);
itt_id_registered = false;
}
#endif
region.pImpl = NULL;
}
void Region::Impl::enterRegion(TraceManagerThreadLocal& ctx)
{
ctx.currentActiveRegion = &region;
if (location.flags & REGION_FLAG_FUNCTION)
{
if ((location.flags & REGION_FLAG_APP_CODE) == 0)
{
ctx.regionDepthOpenCV++;
}
ctx.regionDepth++;
}
TraceStorage* s = ctx.getStorage();
if (s)
{
TraceMessage msg;
msg.formatRegionEnter(region);
s->put(msg);
}
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_id parentID = __itt_null;
if (param_ITT_registerParentScope && parentRegion && parentRegion->pImpl && parentRegion->pImpl->itt_id_registered && (location.flags & REGION_FLAG_REGION_FORCE) == 0)
parentID = parentRegion->pImpl->itt_id;
__itt_task_begin(domain, itt_id, parentID, (*location.ppExtra)->ittHandle_name);
}
#endif
}
void Region::Impl::leaveRegion(TraceManagerThreadLocal& ctx)
{
int64 duration = endTimestamp - beginTimestamp; CV_UNUSED(duration);
RegionStatistics result;
ctx.stat.grab(result);
ctx.totalSkippedEvents += result.currentSkippedRegions;
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "leaveRegion(): " << (void*)this << " " << result);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
if (result.currentSkippedRegions)
{
__itt_metadata_add(domain, itt_id, __itt_string_handle_create("skipped trace entries"), __itt_metadata_u32, 1, &result.currentSkippedRegions);
}
#ifdef HAVE_IPP
if (result.durationImplIPP)
__itt_metadata_add(domain, itt_id, __itt_string_handle_create("tIPP"), __itt_metadata_u64, 1, &result.durationImplIPP);
#endif
#ifdef HAVE_OPENCL
if (result.durationImplOpenCL)
__itt_metadata_add(domain, itt_id, __itt_string_handle_create("tOpenCL"), __itt_metadata_u64, 1, &result.durationImplOpenCL);
#endif
#ifdef HAVE_OPENVX
if (result.durationImplOpenVX)
__itt_metadata_add(domain, itt_id, __itt_string_handle_create("tOpenVX"), __itt_metadata_u64, 1, &result.durationImplOpenVX);
#endif
__itt_task_end(domain);
}
#endif
TraceStorage* s = ctx.getStorage();
if (s)
{
TraceMessage msg;
msg.formatRegionLeave(region, result);
s->put(msg);
}
if (location.flags & REGION_FLAG_FUNCTION)
{
if ((location.flags & REGION_FLAG_APP_CODE) == 0)
{
ctx.regionDepthOpenCV--;
}
ctx.regionDepth--;
}
ctx.currentActiveRegion = parentRegion;
}
void Region::Impl::release()
{
delete this;
}
void Region::Impl::registerRegion(TraceManagerThreadLocal& ctx)
{
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
if (!itt_id_registered)
{
CV_LOG_ITT(" Register ITT region: I=" << (void*)this << " " << ctx.threadID << "-" << global_region_id);
#if 1 // workaround for some ITT backends
itt_id = __itt_id_make((void*)(intptr_t)(((int64)(ctx.threadID + 1) << 32) | global_region_id), global_region_id);
#else
itt_id = __itt_id_make((void*)(intptr_t)(ctx.threadID + 1), global_region_id);
#endif
__itt_id_create(domain, itt_id);
itt_id_registered = true;
}
}
#else
CV_UNUSED(ctx);
#endif
}
void RegionStatisticsStatus::enableSkipMode(int depth)
{
CV_DbgAssert(_skipDepth < 0);
CV_LOG_SKIP(NULL, "SKIP-ENABLE: depth=" << depth);
_skipDepth = depth;
}
void RegionStatisticsStatus::checkResetSkipMode(int leaveDepth)
{
if (leaveDepth <= _skipDepth)
{
CV_LOG_SKIP(NULL, "SKIP-RESET: leaveDepth=" << leaveDepth << " skipDepth=" << _skipDepth);
_skipDepth = -1;
}
}
Region::Region(const LocationStaticStorage& location) :
pImpl(NULL),
implFlags(0)
{
// Checks:
// - global enable flag
// - parent region is disabled
// - children count threshold
// - region location
// - depth (opencv nested calls)
if (!TraceManager::isActivated())
{
CV_LOG("Trace is disabled. Bailout");
return;
}
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "Region(): " << (void*)this << ": " << location.name);
Region* parentRegion = ctx.stackTopRegion();
const Region::LocationStaticStorage* parentLocation = ctx.stackTopLocation();
if (location.flags & REGION_FLAG_REGION_NEXT)
{
if (parentRegion && parentRegion->pImpl)
{
CV_DbgAssert((parentRegion->pImpl->location.flags & REGION_FLAG_FUNCTION) == 0);
parentRegion->destroy(); parentRegion->implFlags = 0;
parentRegion = ctx.stackTopRegion();
parentLocation = ctx.stackTopLocation();
}
}
int parentChildren = 0;
if (parentRegion && parentRegion->pImpl)
{
if (parentLocation == NULL)
{
// parallel_for_body code path
parentChildren = CV_XADD(&parentRegion->pImpl->directChildrenCount, 1) + 1;
}
else
{
parentChildren = ++parentRegion->pImpl->directChildrenCount;
}
}
int64 beginTimestamp = getTimestampNS();
2017-05-25 23:59:01 +08:00
int currentDepth = ctx.getCurrentDepth() + 1;
switch (location.flags & REGION_FLAG_IMPL_MASK)
{
#ifdef HAVE_IPP
case REGION_FLAG_IMPL_IPP:
if (!ctx.stat_status.ignoreDepthImplIPP)
ctx.stat_status.ignoreDepthImplIPP = currentDepth;
break;
#endif
#ifdef HAVE_OPENCL
case REGION_FLAG_IMPL_OPENCL:
if (!ctx.stat_status.ignoreDepthImplOpenCL)
ctx.stat_status.ignoreDepthImplOpenCL = currentDepth;
break;
#endif
#ifdef HAVE_OPENVX
case REGION_FLAG_IMPL_OPENVX:
if (!ctx.stat_status.ignoreDepthImplOpenVX)
ctx.stat_status.ignoreDepthImplOpenVX = currentDepth;
break;
#endif
default:
break;
}
ctx.stackPush(this, &location, beginTimestamp);
implFlags |= REGION_FLAG__NEED_STACK_POP;
if ((location.flags & REGION_FLAG_REGION_FORCE) == 0)
{
if (ctx.stat_status._skipDepth >= 0 && currentDepth > ctx.stat_status._skipDepth)
{
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "Parent region is disabled. Bailout");
ctx.stat.currentSkippedRegions++;
return;
}
if (param_maxRegionChildrenOpenCV > 0 && (location.flags & REGION_FLAG_APP_CODE) == 0 && parentLocation && (parentLocation->flags & REGION_FLAG_APP_CODE) == 0)
{
if (parentChildren >= param_maxRegionChildrenOpenCV)
{
CV_LOG_TRACE_BAILOUT(NULL, _spaces(ctx.getCurrentDepth()*4) << "OpenCV parent region exceeds children count. Bailout");
ctx.stat_status.enableSkipMode(currentDepth - 1);
ctx.stat.currentSkippedRegions++;
DEBUG_ONLY(ctx.dumpStack(std::cout, false));
return;
}
}
if (param_maxRegionChildren > 0 && parentChildren >= param_maxRegionChildren)
{
CV_LOG_TRACE_BAILOUT(NULL, _spaces(ctx.getCurrentDepth()*4) << "Parent region exceeds children count. Bailout");
ctx.stat_status.enableSkipMode(currentDepth - 1);
ctx.stat.currentSkippedRegions++;
DEBUG_ONLY(ctx.dumpStack(std::cout, false));
return;
}
}
LocationExtraData::init(location);
if ((*location.ppExtra)->global_location_id == 0)
{
CV_LOG_TRACE_BAILOUT(NULL, _spaces(ctx.getCurrentDepth()*4) << "Region location is disabled. Bailout");
ctx.stat_status.enableSkipMode(currentDepth);
ctx.stat.currentSkippedRegions++;
return;
}
if (parentLocation && (parentLocation->flags & REGION_FLAG_SKIP_NESTED))
{
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "Parent region disables inner regions. Bailout");
ctx.stat_status.enableSkipMode(currentDepth);
ctx.stat.currentSkippedRegions++;
return;
}
if (param_maxRegionDepthOpenCV)
{
if ((location.flags & REGION_FLAG_APP_CODE) == 0)
{
if (ctx.regionDepthOpenCV >= param_maxRegionDepthOpenCV)
{
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "OpenCV region depth is exceed = " << ctx.regionDepthOpenCV << ". Bailout");
if (ctx.stat.currentSkippedRegions == 0)
{
DEBUG_ONLY(ctx.dumpStack(std::cout, false));
}
ctx.stat_status.enableSkipMode(currentDepth);
ctx.stat.currentSkippedRegions++;
return;
}
}
}
new Impl(ctx, parentRegion, *this, location, beginTimestamp);
CV_DbgAssert(pImpl != NULL);
implFlags |= REGION_FLAG__ACTIVE;
// parallel_for path
if (parentRegion && parentRegion->pImpl)
{
if (parentLocation == NULL)
{
pImpl->directChildrenCount = parentChildren;
}
}
}
void Region::destroy()
{
CV_DbgAssert(implFlags != 0);
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
CV_LOG(_spaces(ctx.getCurrentDepth()*4) << "Region::destruct(): " << (void*)this << " pImpl=" << pImpl << " implFlags=" << implFlags << ' ' << (ctx.stackTopLocation() ? ctx.stackTopLocation()->name : "<unknown>"));
CV_DbgAssert(implFlags & REGION_FLAG__NEED_STACK_POP);
const int currentDepth = ctx.getCurrentDepth(); CV_UNUSED(currentDepth);
CV_LOG_CTX_STAT(NULL, _spaces(currentDepth*4) << ctx.stat << ' ' << ctx.stat_status);
const Region::LocationStaticStorage* location = ctx.stackTopLocation();
Impl::OptimizationPath myCodePath = Impl::CODE_PATH_PLAIN;
if (location)
{
switch (location->flags & REGION_FLAG_IMPL_MASK)
{
#ifdef HAVE_IPP
case REGION_FLAG_IMPL_IPP:
myCodePath = Impl::CODE_PATH_IPP;
break;
#endif
#ifdef HAVE_OPENCL
case REGION_FLAG_IMPL_OPENCL:
if (param_synchronizeOpenCL && cv::ocl::isOpenCLActivated())
2017-05-25 23:59:01 +08:00
cv::ocl::finish();
myCodePath = Impl::CODE_PATH_OPENCL;
break;
#endif
#ifdef HAVE_OPENVX
case REGION_FLAG_IMPL_OPENVX:
myCodePath = Impl::CODE_PATH_OPENVX;
break;
#endif
default:
break;
}
}
int64 endTimestamp = getTimestampNS();
2017-05-25 23:59:01 +08:00
int64 duration = endTimestamp - ctx.stackTopBeginTimestamp();
bool active = isActive();
if (active)
ctx.stat.duration = duration;
else if (ctx.stack.size() == ctx.parallel_for_stack_size + 1)
ctx.stat.duration += duration;
switch (myCodePath) {
case Impl::CODE_PATH_PLAIN:
// nothing
break;
#ifdef HAVE_IPP
case Impl::CODE_PATH_IPP:
if (ctx.stat_status.ignoreDepthImplIPP == currentDepth)
{
ctx.stat.durationImplIPP += duration;
ctx.stat_status.ignoreDepthImplIPP = 0;
}
else if (active)
{
ctx.stat.durationImplIPP = duration;
}
break;
#endif
#ifdef HAVE_OPENCL
case Impl::CODE_PATH_OPENCL:
if (ctx.stat_status.ignoreDepthImplOpenCL == currentDepth)
{
ctx.stat.durationImplOpenCL += duration;
ctx.stat_status.ignoreDepthImplOpenCL = 0;
}
else if (active)
{
ctx.stat.durationImplOpenCL = duration;
}
break;
#endif
#ifdef HAVE_OPENVX
case Impl::CODE_PATH_OPENVX:
if (ctx.stat_status.ignoreDepthImplOpenVX == currentDepth)
{
ctx.stat.durationImplOpenVX += duration;
ctx.stat_status.ignoreDepthImplOpenVX = 0;
}
else if (active)
{
ctx.stat.durationImplOpenVX = duration;
}
break;
#endif
default:
break;
}
if (pImpl)
{
CV_DbgAssert((implFlags & (REGION_FLAG__ACTIVE | REGION_FLAG__NEED_STACK_POP)) == (REGION_FLAG__ACTIVE | REGION_FLAG__NEED_STACK_POP));
CV_DbgAssert(ctx.stackTopRegion() == this);
pImpl->endTimestamp = endTimestamp;
pImpl->leaveRegion(ctx);
pImpl->release();
pImpl = NULL;
DEBUG_ONLY(implFlags &= ~REGION_FLAG__ACTIVE);
}
else
{
CV_DbgAssert(ctx.stat_status._skipDepth <= currentDepth);
}
if (implFlags & REGION_FLAG__NEED_STACK_POP)
{
CV_DbgAssert(ctx.stackTopRegion() == this);
ctx.stackPop();
ctx.stat_status.checkResetSkipMode(currentDepth);
DEBUG_ONLY(implFlags &= ~REGION_FLAG__NEED_STACK_POP);
}
CV_LOG_CTX_STAT(NULL, _spaces(currentDepth*4) << "===> " << ctx.stat << ' ' << ctx.stat_status);
}
TraceManagerThreadLocal::~TraceManagerThreadLocal()
{
}
void TraceManagerThreadLocal::dumpStack(std::ostream& out, bool onlyFunctions) const
{
std::stringstream ss;
std::deque<StackEntry>::const_iterator it = stack.begin();
std::deque<StackEntry>::const_iterator end = stack.end();
int depth = 0;
for (; it != end; ++it)
{
const Region::LocationStaticStorage* location = it->location;
if (location)
{
if (!onlyFunctions || (location->flags & REGION_FLAG_FUNCTION))
{
ss << _spaces(4*depth) << location->name << std::endl;
depth++;
}
}
else
{
ss << _spaces(4*depth) << "<unknown>" << std::endl;
depth++;
}
}
out << ss.str();
}
2018-03-15 21:16:50 +08:00
class AsyncTraceStorage CV_FINAL : public TraceStorage
2017-05-25 23:59:01 +08:00
{
mutable std::ofstream out;
public:
const std::string name;
AsyncTraceStorage(const std::string& filename) :
out(filename.c_str(), std::ios::trunc),
name(filename)
{
out << "#description: OpenCV trace file" << std::endl;
out << "#version: 1.0" << std::endl;
}
~AsyncTraceStorage()
{
out.close();
}
2018-03-15 21:16:50 +08:00
bool put(const TraceMessage& msg) const CV_OVERRIDE
2017-05-25 23:59:01 +08:00
{
if (msg.hasError)
return false;
out << msg.buffer;
//DEBUG_ONLY(std::flush(out)); // TODO configure flag
return true;
}
};
2018-03-15 21:16:50 +08:00
class SyncTraceStorage CV_FINAL : public TraceStorage
2017-05-25 23:59:01 +08:00
{
mutable std::ofstream out;
mutable cv::Mutex mutex;
public:
const std::string name;
SyncTraceStorage(const std::string& filename) :
out(filename.c_str(), std::ios::trunc),
name(filename)
{
out << "#description: OpenCV trace file" << std::endl;
out << "#version: 1.0" << std::endl;
}
~SyncTraceStorage()
{
cv::AutoLock l(mutex);
out.close();
}
2018-03-15 21:16:50 +08:00
bool put(const TraceMessage& msg) const CV_OVERRIDE
2017-05-25 23:59:01 +08:00
{
if (msg.hasError)
return false;
{
cv::AutoLock l(mutex);
out << msg.buffer;
std::flush(out); // TODO configure flag
}
return true;
}
};
TraceStorage* TraceManagerThreadLocal::getStorage() const
{
// TODO configuration option for stdout/single trace file
if (storage.empty())
{
TraceStorage* global = getTraceManager().trace_storage.get();
if (global)
{
const std::string filepath = cv::format("%s-%03d.txt", getParameterTraceLocation().c_str(), threadID).c_str();
2017-05-25 23:59:01 +08:00
TraceMessage msg;
const char* pos = strrchr(filepath.c_str(), '/'); // extract filename
#ifdef _WIN32
if (!pos)
2018-08-20 22:16:54 +08:00
pos = strrchr(filepath.c_str(), '\\');
2017-05-25 23:59:01 +08:00
#endif
if (!pos)
pos = filepath.c_str();
2018-08-20 22:16:54 +08:00
else
pos += 1; // fix to skip extra slash in filename beginning
2017-05-25 23:59:01 +08:00
msg.printf("#thread file: %s\n", pos);
global->put(msg);
storage.reset(new AsyncTraceStorage(filepath));
}
}
return storage.get();
}
static bool activated = false;
static bool isInitialized = false;
TraceManager::TraceManager()
{
(void)cv::getTimestampNS();
2017-05-25 23:59:01 +08:00
isInitialized = true;
CV_LOG("TraceManager ctor: " << (void*)this);
CV_LOG("TraceManager configure()");
activated = getParameterTraceEnable();
2017-05-25 23:59:01 +08:00
if (activated)
trace_storage.reset(new SyncTraceStorage(std::string(getParameterTraceLocation()) + ".txt"));
2017-05-25 23:59:01 +08:00
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
activated = true; // force trace pipeline activation (without OpenCV storage)
__itt_region_begin(domain, __itt_null, __itt_null, __itt_string_handle_create("OpenCVTrace"));
}
#endif
}
TraceManager::~TraceManager()
{
CV_LOG("TraceManager dtor: " << (void*)this);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_region_end(domain, __itt_null);
}
#endif
std::vector<TraceManagerThreadLocal*> threads_ctx;
tls.gather(threads_ctx);
size_t totalEvents = 0, totalSkippedEvents = 0;
for (size_t i = 0; i < threads_ctx.size(); i++)
{
TraceManagerThreadLocal* ctx = threads_ctx[i];
if (ctx)
{
totalEvents += ctx->region_counter;
totalSkippedEvents += ctx->totalSkippedEvents;
}
}
if (totalEvents || activated)
{
CV_LOG_INFO(NULL, "Trace: Total events: " << totalEvents);
}
if (totalSkippedEvents)
{
CV_LOG_WARNING(NULL, "Trace: Total skipped events: " << totalSkippedEvents);
}
// This is a global static object, so process starts shutdown here
// Turn off trace
cv::__termination = true; // also set in DllMain() notifications handler for DLL_PROCESS_DETACH
activated = false;
}
bool TraceManager::isActivated()
{
// Check if process starts shutdown, and set earlyExit to true
// to prevent further instrumentation processing earlier.
if (cv::__termination)
{
activated = false;
return false;
}
if (!isInitialized)
{
TraceManager& m = getTraceManager();
2018-09-07 19:33:52 +08:00
CV_UNUSED(m); // TODO
2017-05-25 23:59:01 +08:00
}
return activated;
}
static TraceManager* getTraceManagerCallOnce()
{
static TraceManager globalInstance;
return &globalInstance;
}
TraceManager& getTraceManager()
{
CV_SINGLETON_LAZY_INIT_REF(TraceManager, getTraceManagerCallOnce())
}
void parallelForSetRootRegion(const Region& rootRegion, const TraceManagerThreadLocal& root_ctx)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
if (ctx.dummy_stack_top.region == &rootRegion) // already attached
return;
CV_Assert(ctx.dummy_stack_top.region == NULL);
ctx.dummy_stack_top = TraceManagerThreadLocal::StackEntry(const_cast<Region*>(&rootRegion), NULL, -1);
if (&ctx == &root_ctx)
{
ctx.stat.grab(ctx.parallel_for_stat);
ctx.parallel_for_stat_status = ctx.stat_status;
ctx.parallel_for_stack_size = ctx.stack.size();
return;
}
CV_Assert(ctx.stack.empty());
ctx.currentActiveRegion = const_cast<Region*>(&rootRegion);
ctx.regionDepth = root_ctx.regionDepth;
ctx.regionDepthOpenCV = root_ctx.regionDepthOpenCV;
ctx.parallel_for_stack_size = 0;
ctx.stat_status.propagateFrom(root_ctx.stat_status);
}
void parallelForAttachNestedRegion(const Region& rootRegion)
{
CV_UNUSED(rootRegion);
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
CV_DbgAssert(ctx.dummy_stack_top.region == &rootRegion);
Region* region = ctx.getCurrentActiveRegion();
CV_LOG_PARALLEL(NULL, " PARALLEL_FOR: " << (void*)region << " ==> " << &rootRegion);
if (!region)
return;
#ifdef OPENCV_WITH_ITT
if (!rootRegion.pImpl || !rootRegion.pImpl->itt_id_registered)
return;
if (!region->pImpl)
return;
CV_LOG_PARALLEL(NULL, " PARALLEL_FOR ITT: " << (void*)rootRegion.pImpl->itt_id.d1 << ":" << rootRegion.pImpl->itt_id.d2 << ":" << (void*)rootRegion.pImpl->itt_id.d3 << " => "
<< (void*)region->pImpl->itt_id.d1 << ":" << region->pImpl->itt_id.d2 << ":" << (void*)region->pImpl->itt_id.d3);
__itt_relation_add(domain, region->pImpl->itt_id, __itt_relation_is_child_of, rootRegion.pImpl->itt_id);
#endif
}
void parallelForFinalize(const Region& rootRegion)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
int64 endTimestamp = getTimestampNS();
2017-05-25 23:59:01 +08:00
int64 duration = endTimestamp - ctx.stackTopBeginTimestamp();
CV_LOG_PARALLEL(NULL, "parallel_for duration: " << duration << " " << &rootRegion);
std::vector<TraceManagerThreadLocal*> threads_ctx;
getTraceManager().tls.gather(threads_ctx);
RegionStatistics parallel_for_stat;
int threads = 0;
for (size_t i = 0; i < threads_ctx.size(); i++)
{
TraceManagerThreadLocal* child_ctx = threads_ctx[i];
if (child_ctx && child_ctx->stackTopRegion() == &rootRegion)
{
CV_LOG_PARALLEL(NULL, "Thread=" << child_ctx->threadID << " " << child_ctx->stat);
threads++;
RegionStatistics child_stat;
child_ctx->stat.grab(child_stat);
parallel_for_stat.append(child_stat);
if (child_ctx != &ctx)
{
child_ctx->dummy_stack_top = TraceManagerThreadLocal::StackEntry();
}
else
{
ctx.parallel_for_stat.grab(ctx.stat);
ctx.stat_status = ctx.parallel_for_stat_status;
child_ctx->dummy_stack_top = TraceManagerThreadLocal::StackEntry();
}
}
}
float parallel_coeff = std::min(1.0f, duration / (float)(parallel_for_stat.duration));
CV_LOG_PARALLEL(NULL, "parallel_coeff=" << 1.0f / parallel_coeff);
CV_LOG_PARALLEL(NULL, parallel_for_stat);
if (parallel_coeff != 1.0f)
{
parallel_for_stat.multiply(parallel_coeff);
CV_LOG_PARALLEL(NULL, parallel_for_stat);
}
parallel_for_stat.duration = 0;
ctx.stat.append(parallel_for_stat);
CV_LOG_PARALLEL(NULL, ctx.stat);
}
struct TraceArg::ExtraData
{
#ifdef OPENCV_WITH_ITT
// Special fields for ITT
__itt_string_handle* volatile ittHandle_name;
#endif
ExtraData(TraceManagerThreadLocal& ctx, const TraceArg& arg)
{
CV_UNUSED(ctx); CV_UNUSED(arg);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
// Caching is not required here, because there is builtin cache.
// https://software.intel.com/en-us/node/544203:
// Consecutive calls to __itt_string_handle_create with the same name return the same value.
ittHandle_name = __itt_string_handle_create(arg.name);
}
else
{
ittHandle_name = 0;
}
2017-05-25 23:59:01 +08:00
#endif
}
};
static void initTraceArg(TraceManagerThreadLocal& ctx, const TraceArg& arg)
{
TraceArg::ExtraData** pExtra = arg.ppExtra;
if (*pExtra == NULL)
{
cv::AutoLock lock(cv::getInitializationMutex());
if (*pExtra == NULL)
{
*pExtra = new TraceArg::ExtraData(ctx, arg);
}
}
}
void traceArg(const TraceArg& arg, const char* value)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
Region* region = ctx.getCurrentActiveRegion();
if (!region)
return;
CV_Assert(region->pImpl);
initTraceArg(ctx, arg);
if (!value)
value = "<null>";
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_metadata_str_add(domain, region->pImpl->itt_id, (*arg.ppExtra)->ittHandle_name, value, strlen(value));
}
#endif
}
void traceArg(const TraceArg& arg, int value)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
Region* region = ctx.getCurrentActiveRegion();
if (!region)
return;
CV_Assert(region->pImpl);
initTraceArg(ctx, arg);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_metadata_add(domain, region->pImpl->itt_id, (*arg.ppExtra)->ittHandle_name, sizeof(int) == 4 ? __itt_metadata_s32 : __itt_metadata_s64, 1, &value);
}
#else
CV_UNUSED(value);
#endif
}
void traceArg(const TraceArg& arg, int64 value)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
Region* region = ctx.getCurrentActiveRegion();
if (!region)
return;
CV_Assert(region->pImpl);
initTraceArg(ctx, arg);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_metadata_add(domain, region->pImpl->itt_id, (*arg.ppExtra)->ittHandle_name, __itt_metadata_s64, 1, &value);
}
#else
CV_UNUSED(value);
#endif
}
void traceArg(const TraceArg& arg, double value)
{
TraceManagerThreadLocal& ctx = getTraceManager().tls.getRef();
Region* region = ctx.getCurrentActiveRegion();
if (!region)
return;
CV_Assert(region->pImpl);
initTraceArg(ctx, arg);
#ifdef OPENCV_WITH_ITT
if (isITTEnabled())
{
__itt_metadata_add(domain, region->pImpl->itt_id, (*arg.ppExtra)->ittHandle_name, __itt_metadata_double, 1, &value);
}
#else
CV_UNUSED(value);
#endif
}
#else
Region::Region(const LocationStaticStorage&) : pImpl(NULL), implFlags(0) {}
void Region::destroy() {}
void traceArg(const TraceArg&, const char*) {}
void traceArg(const TraceArg&, int) {};
void traceArg(const TraceArg&, int64) {};
void traceArg(const TraceArg&, double) {};
#endif
}}}} // namespace