diff --git a/cmake/cl2cpp.cmake b/cmake/cl2cpp.cmake index ed5dcb8761..13918ce5c2 100644 --- a/cmake/cl2cpp.cmake +++ b/cmake/cl2cpp.cmake @@ -12,14 +12,8 @@ endif() string(REPLACE ".cpp" ".hpp" OUTPUT_HPP "${OUTPUT}") get_filename_component(OUTPUT_HPP_NAME "${OUTPUT_HPP}" NAME) -if("${MODULE_NAME}" STREQUAL "ocl") - set(nested_namespace_start "") - set(nested_namespace_end "") -else() - set(new_mode ON) - set(nested_namespace_start "namespace ${MODULE_NAME}\n{") - set(nested_namespace_end "}") -endif() +set(nested_namespace_start "namespace ${MODULE_NAME}\n{") +set(nested_namespace_end "}") set(STR_CPP "// This file is auto-generated. Do not edit! @@ -35,6 +29,8 @@ namespace ocl { ${nested_namespace_start} +static const char* const moduleName = \"${MODULE_NAME}\"; + ") set(STR_HPP "// This file is auto-generated. Do not edit! @@ -76,19 +72,15 @@ foreach(cl ${cl_list}) string(MD5 hash "${lines}") - set(STR_CPP_DECL "const struct ProgramEntry ${cl_filename}={\"${cl_filename}\",\n\"${lines}, \"${hash}\"};\n") - set(STR_HPP_DECL "extern const struct ProgramEntry ${cl_filename};\n") - if(new_mode) - set(STR_CPP_DECL "${STR_CPP_DECL}ProgramSource ${cl_filename}_oclsrc(${cl_filename}.programStr);\n") - set(STR_HPP_DECL "${STR_HPP_DECL}extern ProgramSource ${cl_filename}_oclsrc;\n") - endif() + set(STR_CPP_DECL "struct cv::ocl::internal::ProgramEntry ${cl_filename}_oclsrc={moduleName, \"${cl_filename}\",\n\"${lines}, \"${hash}\", NULL};\n") + set(STR_HPP_DECL "extern struct cv::ocl::internal::ProgramEntry ${cl_filename}_oclsrc;\n") set(STR_CPP "${STR_CPP}${STR_CPP_DECL}") set(STR_HPP "${STR_HPP}${STR_HPP_DECL}") endforeach() -set(STR_CPP "${STR_CPP}}\n${nested_namespace_end}}\n#endif\n") -set(STR_HPP "${STR_HPP}}\n${nested_namespace_end}}\n#endif\n") +set(STR_CPP "${STR_CPP}\n${nested_namespace_end}}}\n#endif\n") +set(STR_HPP "${STR_HPP}\n${nested_namespace_end}}}\n#endif\n") file(WRITE "${OUTPUT}" "${STR_CPP}") @@ -96,7 +88,7 @@ if(EXISTS "${OUTPUT_HPP}") file(READ "${OUTPUT_HPP}" hpp_lines) endif() if("${hpp_lines}" STREQUAL "${STR_HPP}") - message(STATUS "${OUTPUT_HPP} contains same content") + message(STATUS "${OUTPUT_HPP} contains the same content") else() file(WRITE "${OUTPUT_HPP}" "${STR_HPP}") endif() diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp index 1a9549df4c..97c5210d25 100644 --- a/modules/core/include/opencv2/core/ocl.hpp +++ b/modules/core/include/opencv2/core/ocl.hpp @@ -627,17 +627,18 @@ protected: class CV_EXPORTS ProgramSource { public: - typedef uint64 hash_t; + typedef uint64 hash_t; // deprecated ProgramSource(); - explicit ProgramSource(const String& prog); - explicit ProgramSource(const char* prog); + explicit ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash); + explicit ProgramSource(const String& prog); // deprecated + explicit ProgramSource(const char* prog); // deprecated ~ProgramSource(); ProgramSource(const ProgramSource& prog); ProgramSource& operator = (const ProgramSource& prog); const String& source() const; - hash_t hash() const; + hash_t hash() const; // deprecated protected: struct Impl; diff --git a/modules/core/include/opencv2/core/ocl_genbase.hpp b/modules/core/include/opencv2/core/ocl_genbase.hpp index 5408958bc9..5334cf1f4f 100644 --- a/modules/core/include/opencv2/core/ocl_genbase.hpp +++ b/modules/core/include/opencv2/core/ocl_genbase.hpp @@ -42,23 +42,28 @@ #ifndef OPENCV_OPENCL_GENBASE_HPP #define OPENCV_OPENCL_GENBASE_HPP -namespace cv -{ -namespace ocl -{ - //! @cond IGNORED -struct ProgramEntry +namespace cv { +namespace ocl { + +class ProgramSource; + +namespace internal { + +struct CV_EXPORTS ProgramEntry { + const char* module; const char* name; - const char* programStr; + const char* programCode; const char* programHash; + ProgramSource* pProgramSource; + + operator ProgramSource& () const; }; +} } } // namespace + //! @endcond -} -} - #endif diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 2f51adcfc0..7e03a241af 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -49,6 +49,8 @@ #include #endif +#include "opencv2/core/ocl_genbase.hpp" + #define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0 #define CV_OPENCL_SHOW_RUN_ERRORS 0 #define CV_OPENCL_SHOW_SVM_ERROR_LOG 1 @@ -1259,6 +1261,18 @@ static unsigned int getSVMCapabilitiesMask() } // namespace #endif +static size_t getProgramCountLimit() +{ + static bool initialized = false; + static size_t count = 0; + if (!initialized) + { + count = getConfigurationParameterForSize("OPENCV_OPENCL_PROGRAM_CACHE", 64); + initialized = true; + } + return count; +} + struct Context::Impl { static Context::Impl* get(Context& context) { return context.p; } @@ -1378,35 +1392,57 @@ struct Context::Impl Program getProg(const ProgramSource& src, const String& buildflags, String& errmsg) { - String prefix = Program::getPrefix(buildflags); - HashKey k(src.hash(), crc64((const uchar*)prefix.c_str(), prefix.size())); - phash_t::iterator it = phash.find(k); - if( it != phash.end() ) - return it->second; - //String filename = format("%08x%08x_%08x%08x.clb2", + size_t limit = getProgramCountLimit(); + String key = Program::getPrefix(buildflags); + { + cv::AutoLock lock(program_cache_mutex); + phash_t::iterator it = phash.find(key); + if (it != phash.end()) + { + // TODO LRU cache + CacheList::iterator i = std::find(cacheList.begin(), cacheList.end(), key); + if (i != cacheList.end() && i != cacheList.begin()) + { + cacheList.erase(i); + cacheList.push_front(key); + } + return it->second; + } + { // cleanup program cache + size_t sz = phash.size(); + if (limit > 0 && sz >= limit) + { + while (!cacheList.empty()) + { + size_t c = phash.erase(cacheList.back()); + cacheList.pop_back(); + if (c != 0) + break; + } + } + } + } Program prog(src, buildflags, errmsg); if(prog.ptr()) - phash.insert(std::pair(k, prog)); + { + cv::AutoLock lock(program_cache_mutex); + phash.insert(std::pair(key, prog)); + cacheList.push_front(key); + } return prog; } + IMPLEMENT_REFCOUNTABLE(); cl_context handle; std::vector devices; - typedef ProgramSource::hash_t hash_t; - - struct HashKey - { - HashKey(hash_t _a, hash_t _b) : a(_a), b(_b) {} - bool operator < (const HashKey& k) const { return a < k.a || (a == k.a && b < k.b); } - bool operator == (const HashKey& k) const { return a == k.a && b == k.b; } - bool operator != (const HashKey& k) const { return a != k.a || b != k.b; } - hash_t a, b; - }; - typedef std::map phash_t; + cv::Mutex program_cache_mutex; + typedef std::map phash_t; phash_t phash; + typedef std::list CacheList; + CacheList cacheList; #ifdef HAVE_OPENCL_SVM bool svmInitialized; @@ -2580,24 +2616,46 @@ String Program::getPrefix(const String& buildflags) struct ProgramSource::Impl { - Impl(const char* _src) + Impl(const String& src) { - init(String(_src)); + init(cv::String(), cv::String(), src, cv::String()); } - Impl(const String& _src) + Impl(const String& module, const String& name, const String& codeStr, const String& codeHash) { - init(_src); + init(module, name, codeStr, codeHash); } - void init(const String& _src) + void init(const String& module, const String& name, const String& codeStr, const String& codeHash) { refcount = 1; - src = _src; - h = crc64((uchar*)src.c_str(), src.size()); + module_ = module; + name_ = name; + codeStr_ = codeStr; + codeHash_ = codeHash; + + isHashUpdated = false; + if (codeHash_.empty()) + { + updateHash(); + codeHash_ = cv::format("%08llx", hash_); + } + } + + void updateHash() + { + hash_ = crc64((uchar*)codeStr_.c_str(), codeStr_.size()); + isHashUpdated = true; } IMPLEMENT_REFCOUNTABLE(); - String src; - ProgramSource::hash_t h; + + String module_; + String name_; + String codeStr_; + String codeHash_; + // TODO std::vector includes_; + + bool isHashUpdated; + ProgramSource::hash_t hash_; }; @@ -2606,6 +2664,11 @@ ProgramSource::ProgramSource() p = 0; } +ProgramSource::ProgramSource(const String& module, const String& name, const String& codeStr, const String& codeHash) +{ + p = new Impl(module, name, codeStr, codeHash); +} + ProgramSource::ProgramSource(const char* prog) { p = new Impl(prog); @@ -2642,15 +2705,34 @@ ProgramSource& ProgramSource::operator = (const ProgramSource& prog) const String& ProgramSource::source() const { - static String dummy; - return p ? p->src : dummy; + CV_Assert(p); + return p->codeStr_; } ProgramSource::hash_t ProgramSource::hash() const { - return p ? p->h : 0; + CV_Assert(p); + if (!p->isHashUpdated) + p->updateHash(); + return p->hash_; } + +internal::ProgramEntry::operator ProgramSource&() const +{ + if (this->pProgramSource == NULL) + { + cv::AutoLock lock(cv::getInitializationMutex()); + if (this->pProgramSource == NULL) + { + ProgramSource* ps = new ProgramSource(this->module, this->name, this->programCode, this->programHash); + const_cast(this)->pProgramSource = ps; + } + } + return *this->pProgramSource; +} + + //////////////////////////////////////////// OpenCLAllocator ////////////////////////////////////////////////// template