Merge pull request #15692 from alalek:core_tls_handle_thread_termination
This commit is contained in:
@@ -53,6 +53,10 @@
|
||||
|
||||
#include <opencv2/core/utils/trace.hpp>
|
||||
|
||||
#ifdef ENABLE_INSTRUMENTATION
|
||||
#include "opencv2/core/utils/instrumentation.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EIGEN
|
||||
# if defined __GNUC__ && defined __APPLE__
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
|
||||
@@ -63,30 +63,6 @@
|
||||
namespace cv
|
||||
{
|
||||
|
||||
#ifdef CV_COLLECT_IMPL_DATA
|
||||
CV_EXPORTS void setImpl(int flags); // set implementation flags and reset storage arrays
|
||||
CV_EXPORTS void addImpl(int flag, const char* func = 0); // add implementation and function name to storage arrays
|
||||
// Get stored implementation flags and functions names arrays
|
||||
// Each implementation entry correspond to function name entry, so you can find which implementation was executed in which function
|
||||
CV_EXPORTS int getImpl(std::vector<int> &impl, std::vector<String> &funName);
|
||||
|
||||
CV_EXPORTS bool useCollection(); // return implementation collection state
|
||||
CV_EXPORTS void setUseCollection(bool flag); // set implementation collection state
|
||||
|
||||
#define CV_IMPL_PLAIN 0x01 // native CPU OpenCV implementation
|
||||
#define CV_IMPL_OCL 0x02 // OpenCL implementation
|
||||
#define CV_IMPL_IPP 0x04 // IPP implementation
|
||||
#define CV_IMPL_MT 0x10 // multithreaded implementation
|
||||
|
||||
#define CV_IMPL_ADD(impl) \
|
||||
if(cv::useCollection()) \
|
||||
{ \
|
||||
cv::addImpl(impl, CV_Func); \
|
||||
}
|
||||
#else
|
||||
#define CV_IMPL_ADD(impl)
|
||||
#endif
|
||||
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
@@ -726,61 +702,6 @@ private:
|
||||
AutoLock& operator = (const AutoLock&);
|
||||
};
|
||||
|
||||
// TLS interface
|
||||
class CV_EXPORTS TLSDataContainer
|
||||
{
|
||||
protected:
|
||||
TLSDataContainer();
|
||||
virtual ~TLSDataContainer();
|
||||
|
||||
void gatherData(std::vector<void*> &data) const;
|
||||
#if OPENCV_ABI_COMPATIBILITY > 300
|
||||
void* getData() const;
|
||||
void release();
|
||||
|
||||
private:
|
||||
#else
|
||||
void release();
|
||||
|
||||
public:
|
||||
void* getData() const;
|
||||
#endif
|
||||
virtual void* createDataInstance() const = 0;
|
||||
virtual void deleteDataInstance(void* pData) const = 0;
|
||||
|
||||
int key_;
|
||||
|
||||
public:
|
||||
void cleanup(); //! Release created TLS data container objects. It is similar to release() call, but it keeps TLS container valid.
|
||||
};
|
||||
|
||||
// Main TLS data class
|
||||
template <typename T>
|
||||
class TLSData : protected TLSDataContainer
|
||||
{
|
||||
public:
|
||||
inline TLSData() {}
|
||||
inline ~TLSData() { release(); } // Release key and delete associated data
|
||||
inline T* get() const { return (T*)getData(); } // Get data associated with key
|
||||
inline T& getRef() const { T* ptr = (T*)getData(); CV_Assert(ptr); return *ptr; } // Get data associated with key
|
||||
|
||||
// Get data from all threads
|
||||
inline void gather(std::vector<T*> &data) const
|
||||
{
|
||||
std::vector<void*> &dataVoid = reinterpret_cast<std::vector<void*>&>(data);
|
||||
gatherData(dataVoid);
|
||||
}
|
||||
|
||||
inline void cleanup() { TLSDataContainer::cleanup(); }
|
||||
|
||||
private:
|
||||
virtual void* createDataInstance() const CV_OVERRIDE {return new T;} // Wrapper to allocate data by template
|
||||
virtual void deleteDataInstance(void* pData) const CV_OVERRIDE {delete (T*)pData;} // Wrapper to release data by template
|
||||
|
||||
// Disable TLS copy operations
|
||||
TLSData(TLSData &) {}
|
||||
TLSData& operator =(const TLSData &) {return *this;}
|
||||
};
|
||||
|
||||
/** @brief Designed for command line parsing
|
||||
|
||||
@@ -1199,88 +1120,6 @@ public:
|
||||
std::vector<Node<OBJECT>*> m_childs;
|
||||
};
|
||||
|
||||
// Instrumentation external interface
|
||||
namespace instr
|
||||
{
|
||||
|
||||
#if !defined OPENCV_ABI_CHECK
|
||||
|
||||
enum TYPE
|
||||
{
|
||||
TYPE_GENERAL = 0, // OpenCV API function, e.g. exported function
|
||||
TYPE_MARKER, // Information marker
|
||||
TYPE_WRAPPER, // Wrapper function for implementation
|
||||
TYPE_FUN, // Simple function call
|
||||
};
|
||||
|
||||
enum IMPL
|
||||
{
|
||||
IMPL_PLAIN = 0,
|
||||
IMPL_IPP,
|
||||
IMPL_OPENCL,
|
||||
};
|
||||
|
||||
struct NodeDataTls
|
||||
{
|
||||
NodeDataTls()
|
||||
{
|
||||
m_ticksTotal = 0;
|
||||
}
|
||||
uint64 m_ticksTotal;
|
||||
};
|
||||
|
||||
class CV_EXPORTS NodeData
|
||||
{
|
||||
public:
|
||||
NodeData(const char* funName = 0, const char* fileName = NULL, int lineNum = 0, void* retAddress = NULL, bool alwaysExpand = false, cv::instr::TYPE instrType = TYPE_GENERAL, cv::instr::IMPL implType = IMPL_PLAIN);
|
||||
NodeData(NodeData &ref);
|
||||
~NodeData();
|
||||
NodeData& operator=(const NodeData&);
|
||||
|
||||
cv::String m_funName;
|
||||
cv::instr::TYPE m_instrType;
|
||||
cv::instr::IMPL m_implType;
|
||||
const char* m_fileName;
|
||||
int m_lineNum;
|
||||
void* m_retAddress;
|
||||
bool m_alwaysExpand;
|
||||
bool m_funError;
|
||||
|
||||
volatile int m_counter;
|
||||
volatile uint64 m_ticksTotal;
|
||||
TLSData<NodeDataTls> m_tls;
|
||||
int m_threads;
|
||||
|
||||
// No synchronization
|
||||
double getTotalMs() const { return ((double)m_ticksTotal / cv::getTickFrequency()) * 1000; }
|
||||
double getMeanMs() const { return (((double)m_ticksTotal/m_counter) / cv::getTickFrequency()) * 1000; }
|
||||
};
|
||||
bool operator==(const NodeData& lhs, const NodeData& rhs);
|
||||
|
||||
typedef Node<NodeData> InstrNode;
|
||||
|
||||
CV_EXPORTS InstrNode* getTrace();
|
||||
|
||||
#endif // !defined OPENCV_ABI_CHECK
|
||||
|
||||
|
||||
CV_EXPORTS bool useInstrumentation();
|
||||
CV_EXPORTS void setUseInstrumentation(bool flag);
|
||||
CV_EXPORTS void resetTrace();
|
||||
|
||||
enum FLAGS
|
||||
{
|
||||
FLAGS_NONE = 0,
|
||||
FLAGS_MAPPING = 0x01,
|
||||
FLAGS_EXPAND_SAME_NAMES = 0x02,
|
||||
};
|
||||
|
||||
CV_EXPORTS void setFlags(FLAGS modeFlags);
|
||||
static inline void setFlags(int modeFlags) { setFlags((FLAGS)modeFlags); }
|
||||
CV_EXPORTS FLAGS getFlags();
|
||||
|
||||
} // namespace instr
|
||||
|
||||
|
||||
namespace samples {
|
||||
|
||||
@@ -1355,6 +1194,13 @@ CV_EXPORTS int getThreadID();
|
||||
|
||||
} //namespace cv
|
||||
|
||||
#ifdef CV_COLLECT_IMPL_DATA
|
||||
#include "opencv2/core/utils/instrumentation.hpp"
|
||||
#else
|
||||
/// Collect implementation data on OpenCV function call. Requires ENABLE_IMPL_COLLECTION build option.
|
||||
#define CV_IMPL_ADD(impl)
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_OPENCV_24_COMPATIBILITY
|
||||
#include "opencv2/core/core_c.h"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
// 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_INSTR_HPP
|
||||
#define OPENCV_UTILS_INSTR_HPP
|
||||
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/core/utils/tls.hpp>
|
||||
|
||||
namespace cv {
|
||||
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
#ifdef CV_COLLECT_IMPL_DATA
|
||||
CV_EXPORTS void setImpl(int flags); // set implementation flags and reset storage arrays
|
||||
CV_EXPORTS void addImpl(int flag, const char* func = 0); // add implementation and function name to storage arrays
|
||||
// Get stored implementation flags and functions names arrays
|
||||
// Each implementation entry correspond to function name entry, so you can find which implementation was executed in which function
|
||||
CV_EXPORTS int getImpl(std::vector<int> &impl, std::vector<String> &funName);
|
||||
|
||||
CV_EXPORTS bool useCollection(); // return implementation collection state
|
||||
CV_EXPORTS void setUseCollection(bool flag); // set implementation collection state
|
||||
|
||||
#define CV_IMPL_PLAIN 0x01 // native CPU OpenCV implementation
|
||||
#define CV_IMPL_OCL 0x02 // OpenCL implementation
|
||||
#define CV_IMPL_IPP 0x04 // IPP implementation
|
||||
#define CV_IMPL_MT 0x10 // multithreaded implementation
|
||||
|
||||
#undef CV_IMPL_ADD
|
||||
#define CV_IMPL_ADD(impl) \
|
||||
if(cv::useCollection()) \
|
||||
{ \
|
||||
cv::addImpl(impl, CV_Func); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Instrumentation external interface
|
||||
namespace instr
|
||||
{
|
||||
|
||||
#if !defined OPENCV_ABI_CHECK
|
||||
|
||||
enum TYPE
|
||||
{
|
||||
TYPE_GENERAL = 0, // OpenCV API function, e.g. exported function
|
||||
TYPE_MARKER, // Information marker
|
||||
TYPE_WRAPPER, // Wrapper function for implementation
|
||||
TYPE_FUN, // Simple function call
|
||||
};
|
||||
|
||||
enum IMPL
|
||||
{
|
||||
IMPL_PLAIN = 0,
|
||||
IMPL_IPP,
|
||||
IMPL_OPENCL,
|
||||
};
|
||||
|
||||
struct NodeDataTls
|
||||
{
|
||||
NodeDataTls()
|
||||
{
|
||||
m_ticksTotal = 0;
|
||||
}
|
||||
uint64 m_ticksTotal;
|
||||
};
|
||||
|
||||
class CV_EXPORTS NodeData
|
||||
{
|
||||
public:
|
||||
NodeData(const char* funName = 0, const char* fileName = NULL, int lineNum = 0, void* retAddress = NULL, bool alwaysExpand = false, cv::instr::TYPE instrType = TYPE_GENERAL, cv::instr::IMPL implType = IMPL_PLAIN);
|
||||
NodeData(NodeData &ref);
|
||||
~NodeData();
|
||||
NodeData& operator=(const NodeData&);
|
||||
|
||||
cv::String m_funName;
|
||||
cv::instr::TYPE m_instrType;
|
||||
cv::instr::IMPL m_implType;
|
||||
const char* m_fileName;
|
||||
int m_lineNum;
|
||||
void* m_retAddress;
|
||||
bool m_alwaysExpand;
|
||||
bool m_funError;
|
||||
|
||||
volatile int m_counter;
|
||||
volatile uint64 m_ticksTotal;
|
||||
TLSDataAccumulator<NodeDataTls> m_tls;
|
||||
int m_threads;
|
||||
|
||||
// No synchronization
|
||||
double getTotalMs() const { return ((double)m_ticksTotal / cv::getTickFrequency()) * 1000; }
|
||||
double getMeanMs() const { return (((double)m_ticksTotal/m_counter) / cv::getTickFrequency()) * 1000; }
|
||||
};
|
||||
bool operator==(const NodeData& lhs, const NodeData& rhs);
|
||||
|
||||
typedef Node<NodeData> InstrNode;
|
||||
|
||||
CV_EXPORTS InstrNode* getTrace();
|
||||
|
||||
#endif // !defined OPENCV_ABI_CHECK
|
||||
|
||||
|
||||
CV_EXPORTS bool useInstrumentation();
|
||||
CV_EXPORTS void setUseInstrumentation(bool flag);
|
||||
CV_EXPORTS void resetTrace();
|
||||
|
||||
enum FLAGS
|
||||
{
|
||||
FLAGS_NONE = 0,
|
||||
FLAGS_MAPPING = 0x01,
|
||||
FLAGS_EXPAND_SAME_NAMES = 0x02,
|
||||
};
|
||||
|
||||
CV_EXPORTS void setFlags(FLAGS modeFlags);
|
||||
static inline void setFlags(int modeFlags) { setFlags((FLAGS)modeFlags); }
|
||||
CV_EXPORTS FLAGS getFlags();
|
||||
|
||||
} // namespace instr
|
||||
|
||||
//! @}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // OPENCV_UTILS_TLS_HPP
|
||||
@@ -0,0 +1,237 @@
|
||||
// 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_TLS_HPP
|
||||
#define OPENCV_UTILS_TLS_HPP
|
||||
|
||||
#include <opencv2/core/utility.hpp>
|
||||
|
||||
namespace cv {
|
||||
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
namespace details { class TlsStorage; }
|
||||
|
||||
/** TLS container base implementation
|
||||
*
|
||||
* Don't use directly.
|
||||
*
|
||||
* @sa TLSData, TLSDataAccumulator templates
|
||||
*/
|
||||
class CV_EXPORTS TLSDataContainer
|
||||
{
|
||||
protected:
|
||||
TLSDataContainer();
|
||||
virtual ~TLSDataContainer();
|
||||
|
||||
/// @deprecated use detachData() instead
|
||||
void gatherData(std::vector<void*> &data) const;
|
||||
/// get TLS data and detach all data from threads (similar to cleanup() call)
|
||||
void detachData(std::vector<void*>& data);
|
||||
|
||||
void* getData() const;
|
||||
void release();
|
||||
|
||||
protected:
|
||||
virtual void* createDataInstance() const = 0;
|
||||
virtual void deleteDataInstance(void* pData) const = 0;
|
||||
|
||||
#if OPENCV_ABI_COMPATIBILITY > 300
|
||||
private:
|
||||
#else
|
||||
public:
|
||||
#endif
|
||||
int key_;
|
||||
|
||||
friend class cv::details::TlsStorage; // core/src/system.cpp
|
||||
|
||||
public:
|
||||
void cleanup(); //!< Release created TLS data container objects. It is similar to release() call, but it keeps TLS container valid.
|
||||
|
||||
private:
|
||||
// Disable copy/assign (noncopyable pattern)
|
||||
TLSDataContainer(TLSDataContainer &);
|
||||
TLSDataContainer& operator =(const TLSDataContainer &);
|
||||
};
|
||||
|
||||
|
||||
/** @brief Simple TLS data class
|
||||
*
|
||||
* @sa TLSDataAccumulator
|
||||
*/
|
||||
template <typename T>
|
||||
class TLSData : protected TLSDataContainer
|
||||
{
|
||||
public:
|
||||
inline TLSData() {}
|
||||
inline ~TLSData() { release(); }
|
||||
|
||||
inline T* get() const { return (T*)getData(); } //!< Get data associated with key
|
||||
inline T& getRef() const { T* ptr = (T*)getData(); CV_DbgAssert(ptr); return *ptr; } //!< Get data associated with key
|
||||
|
||||
/// Release associated thread data
|
||||
inline void cleanup()
|
||||
{
|
||||
TLSDataContainer::cleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Wrapper to allocate data by template
|
||||
virtual void* createDataInstance() const CV_OVERRIDE { return new T; }
|
||||
/// Wrapper to release data by template
|
||||
virtual void deleteDataInstance(void* pData) const CV_OVERRIDE { delete (T*)pData; }
|
||||
};
|
||||
|
||||
|
||||
/// TLS data accumulator with gathering methods
|
||||
template <typename T>
|
||||
class TLSDataAccumulator : public TLSData<T>
|
||||
{
|
||||
mutable cv::Mutex mutex;
|
||||
mutable std::vector<T*> dataFromTerminatedThreads;
|
||||
std::vector<T*> detachedData;
|
||||
bool cleanupMode;
|
||||
public:
|
||||
TLSDataAccumulator() : cleanupMode(false) {}
|
||||
~TLSDataAccumulator()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
/** @brief Get data from all threads
|
||||
* @deprecated replaced by detachData()
|
||||
*
|
||||
* Lifetime of vector data is valid until next detachData()/cleanup()/release() calls
|
||||
*
|
||||
* @param[out] data result buffer (should be empty)
|
||||
*/
|
||||
void gather(std::vector<T*> &data) const
|
||||
{
|
||||
CV_Assert(cleanupMode == false); // state is not valid
|
||||
CV_Assert(data.empty());
|
||||
{
|
||||
std::vector<void*> &dataVoid = reinterpret_cast<std::vector<void*>&>(data);
|
||||
TLSDataContainer::gatherData(dataVoid);
|
||||
}
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
data.reserve(data.size() + dataFromTerminatedThreads.size());
|
||||
for (typename std::vector<T*>::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
data.push_back((T*)*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Get and detach data from all threads
|
||||
*
|
||||
* Call cleanupDetachedData() when returned vector is not needed anymore.
|
||||
*
|
||||
* @return Vector with associated data. Content is preserved (including lifetime of attached data pointers) until next detachData()/cleanupDetachedData()/cleanup()/release() calls
|
||||
*/
|
||||
std::vector<T*>& detachData()
|
||||
{
|
||||
CV_Assert(cleanupMode == false); // state is not valid
|
||||
std::vector<void*> dataVoid;
|
||||
{
|
||||
TLSDataContainer::detachData(dataVoid);
|
||||
}
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
detachedData.reserve(dataVoid.size() + dataFromTerminatedThreads.size());
|
||||
for (typename std::vector<T*>::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
detachedData.push_back((T*)*i);
|
||||
}
|
||||
dataFromTerminatedThreads.clear();
|
||||
for (typename std::vector<void*>::const_iterator i = dataVoid.begin(); i != dataVoid.end(); ++i)
|
||||
{
|
||||
detachedData.push_back((T*)(void*)*i);
|
||||
}
|
||||
}
|
||||
dataVoid.clear();
|
||||
return detachedData;
|
||||
}
|
||||
|
||||
/// Release associated thread data returned by detachData() call
|
||||
void cleanupDetachedData()
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
cleanupMode = true;
|
||||
_cleanupDetachedData();
|
||||
cleanupMode = false;
|
||||
}
|
||||
|
||||
/// Release associated thread data
|
||||
void cleanup()
|
||||
{
|
||||
cleanupMode = true;
|
||||
TLSDataContainer::cleanup();
|
||||
|
||||
AutoLock lock(mutex);
|
||||
_cleanupDetachedData();
|
||||
_cleanupTerminatedData();
|
||||
cleanupMode = false;
|
||||
}
|
||||
|
||||
/// Release associated thread data and free TLS key
|
||||
void release()
|
||||
{
|
||||
cleanupMode = true;
|
||||
TLSDataContainer::release();
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
_cleanupDetachedData();
|
||||
_cleanupTerminatedData();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// synchronized
|
||||
void _cleanupDetachedData()
|
||||
{
|
||||
for (typename std::vector<T*>::iterator i = detachedData.begin(); i != detachedData.end(); ++i)
|
||||
{
|
||||
deleteDataInstance((T*)*i);
|
||||
}
|
||||
detachedData.clear();
|
||||
}
|
||||
|
||||
// synchronized
|
||||
void _cleanupTerminatedData()
|
||||
{
|
||||
for (typename std::vector<T*>::iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
deleteDataInstance((T*)*i);
|
||||
}
|
||||
dataFromTerminatedThreads.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void* createDataInstance() const CV_OVERRIDE
|
||||
{
|
||||
// Note: we can collect all allocated data here, but this would require raced mutex locks
|
||||
return new T;
|
||||
}
|
||||
virtual void deleteDataInstance(void* pData) const CV_OVERRIDE
|
||||
{
|
||||
if (cleanupMode)
|
||||
{
|
||||
delete (T*)pData;
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
dataFromTerminatedThreads.push_back((T*)pData);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! @}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // OPENCV_UTILS_TLS_HPP
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#include <opencv2/core/utils/tls.hpp>
|
||||
|
||||
#include "trace.hpp"
|
||||
|
||||
//! @cond IGNORED
|
||||
@@ -332,7 +334,7 @@ public:
|
||||
Mutex mutexCreate;
|
||||
Mutex mutexCount;
|
||||
|
||||
TLSData<TraceManagerThreadLocal> tls;
|
||||
TLSDataAccumulator<TraceManagerThreadLocal> tls;
|
||||
|
||||
cv::Ptr<TraceStorage> trace_storage;
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user