Entries with the same platform name, the same device name and with different driver versions
are assumed obsolete.
CV_EXPORTS bool exists(const cv::String& path);
CV_EXPORTS bool isDirectory(const cv::String& path);
+CV_EXPORTS void remove_all(const cv::String& path);
+
CV_EXPORTS cv::String getcwd();
+/** Join path components */
+CV_EXPORTS cv::String join(const cv::String& base, const cv::String& path);
+
+/**
+ * Generate a list of all files that match the globbing pattern.
+ *
+ * Result entries are prefixed by base directory path.
+ *
+ * @param directory base directory
+ * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results
+ * @param[out] result result of globing.
+ * @param recursive scan nested directories too
+ * @param includeDirectories include directories into results list
+ */
+CV_EXPORTS void glob(const cv::String& directory, const cv::String& pattern,
+ CV_OUT std::vector<cv::String>& result,
+ bool recursive = false, bool includeDirectories = false);
+
+/**
+ * Generate a list of all files that match the globbing pattern.
+ *
+ * @param directory base directory
+ * @param pattern filter pattern (based on '*'/'?' symbols). Use empty string to disable filtering and return all results
+ * @param[out] result globbing result with relative paths from base directory
+ * @param recursive scan nested directories too
+ * @param includeDirectories include directories into results list
+ */
+CV_EXPORTS void glob_relative(const cv::String& directory, const cv::String& pattern,
+ CV_OUT std::vector<cv::String>& result,
+ bool recursive = false, bool includeDirectories = false);
+
CV_EXPORTS bool createDirectory(const cv::String& path);
CV_EXPORTS bool createDirectories(const cv::String& path);
#endif
-#define CV_LOG_FATAL(tag, ...) for(;;) { std::stringstream ss; ss << "[FATAL:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str(); break; }
-#define CV_LOG_ERROR(tag, ...) for(;;) { std::stringstream ss; ss << "[ERROR:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str(); break; }
-#define CV_LOG_WARNING(tag, ...) for(;;) { std::stringstream ss; ss << "[ WARN:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str(); break; }
+#define CV_LOG_FATAL(tag, ...) for(;;) { std::stringstream ss; ss << "[FATAL:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str() << std::flush; break; }
+#define CV_LOG_ERROR(tag, ...) for(;;) { std::stringstream ss; ss << "[ERROR:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str() << std::flush; break; }
+#define CV_LOG_WARNING(tag, ...) for(;;) { std::stringstream ss; ss << "[ WARN:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str() << std::flush; break; }
#if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
#define CV_LOG_INFO(tag, ...)
#else
#if defined _WIN32 || defined WINCE
# include <windows.h>
const char dir_separators[] = "/\\";
-const char native_separator = '\\';
namespace
{
# include <dirent.h>
# include <sys/stat.h>
const char dir_separators[] = "/";
-const char native_separator = '/';
#endif
static bool isDir(const cv::String& path, DIR* dir)
return *wild == 0;
}
-static void glob_rec(const cv::String& directory, const cv::String& wildchart, std::vector<cv::String>& result, bool recursive)
+static void glob_rec(const cv::String& directory, const cv::String& wildchart, std::vector<cv::String>& result,
+ bool recursive, bool includeDirectories, const cv::String& pathPrefix)
{
DIR *dir;
- struct dirent *ent;
if ((dir = opendir (directory.c_str())) != 0)
{
/* find all the files and directories within directory */
try
{
+ struct dirent *ent;
while ((ent = readdir (dir)) != 0)
{
const char* name = ent->d_name;
if((name[0] == 0) || (name[0] == '.' && name[1] == 0) || (name[0] == '.' && name[1] == '.' && name[2] == 0))
continue;
- cv::String path = directory + native_separator + name;
+ cv::String path = cv::utils::fs::join(directory, name);
+ cv::String entry = cv::utils::fs::join(pathPrefix, name);
if (isDir(path, dir))
{
if (recursive)
- glob_rec(path, wildchart, result, recursive);
- }
- else
- {
- if (wildchart.empty() || wildcmp(name, wildchart.c_str()))
- result.push_back(path);
+ glob_rec(path, wildchart, result, recursive, includeDirectories, entry);
+ if (!includeDirectories)
+ continue;
}
+
+ if (wildchart.empty() || wildcmp(name, wildchart.c_str()))
+ result.push_back(entry);
}
}
catch (...)
}
closedir(dir);
}
- else CV_Error(CV_StsObjectNotFound, cv::format("could not open directory: %s", directory.c_str()));
+ else
+ {
+ CV_Error_(CV_StsObjectNotFound, ("could not open directory: %s", directory.c_str()));
+ }
}
void cv::glob(String pattern, std::vector<String>& result, bool recursive)
}
}
- glob_rec(path, wildchart, result, recursive);
+ glob_rec(path, wildchart, result, recursive, false, path);
+ std::sort(result.begin(), result.end());
+}
+
+void cv::utils::fs::glob(const cv::String& directory, const cv::String& pattern,
+ std::vector<cv::String>& result,
+ bool recursive, bool includeDirectories)
+{
+ glob_rec(directory, pattern, result, recursive, includeDirectories, directory);
+ std::sort(result.begin(), result.end());
+}
+
+void cv::utils::fs::glob_relative(const cv::String& directory, const cv::String& pattern,
+ std::vector<cv::String>& result,
+ bool recursive, bool includeDirectories)
+{
+ glob_rec(directory, pattern, result, recursive, includeDirectories, cv::String());
std::sort(result.begin(), result.end());
}
static const bool CV_OPENCL_CACHE_ENABLE = utils::getConfigurationParameterBool("OPENCV_OPENCL_CACHE_ENABLE", true);
static const bool CV_OPENCL_CACHE_WRITE = utils::getConfigurationParameterBool("OPENCV_OPENCL_CACHE_WRITE", true);
static const bool CV_OPENCL_CACHE_LOCK_ENABLE = utils::getConfigurationParameterBool("OPENCV_OPENCL_CACHE_LOCK_ENABLE", true);
+static const bool CV_OPENCL_CACHE_CLEANUP = utils::getConfigurationParameterBool("OPENCV_OPENCL_CACHE_CLEANUP", true);
#if CV_OPENCL_VALIDATE_BINARY_PROGRAMS
static const bool CV_OPENCL_VALIDATE_BINARY_PROGRAMS_VALUE = utils::getConfigurationParameterBool("OPENCV_OPENCL_VALIDATE_BINARY_PROGRAMS", false);
typedef std::map<std::string, std::string> ContextCacheType;
ContextCacheType prepared_contexts_;
+ Mutex mutex_prepared_contexts_;
OpenCLBinaryCacheConfigurator()
{
cache_lock_.release();
}
- std::string prepareCacheDirectoryForContext(const std::string& ctx_prefix)
+ std::string prepareCacheDirectoryForContext(const std::string& ctx_prefix,
+ const std::string& cleanup_prefix)
{
if (cache_path_.empty())
return std::string();
- ContextCacheType::iterator i = prepared_contexts_.find(ctx_prefix);
- if (i != prepared_contexts_.end())
- return i->second;
+ AutoLock lock(mutex_prepared_contexts_);
+
+ ContextCacheType::iterator found_it = prepared_contexts_.find(ctx_prefix);
+ if (found_it != prepared_contexts_.end())
+ return found_it->second;
CV_LOG_INFO(NULL, "Preparing OpenCL cache configuration for context: " << ctx_prefix);
target_directory = result ? target_directory : std::string();
prepared_contexts_.insert(std::pair<std::string, std::string>(ctx_prefix, target_directory));
- CV_LOG_VERBOSE(NULL, 1, " Result: " << (target_directory.empty() ? std::string("Failed") : target_directory));
+ if (result && CV_OPENCL_CACHE_CLEANUP && CV_OPENCL_CACHE_WRITE && !cleanup_prefix.empty())
+ {
+ try
+ {
+ std::vector<String> entries;
+ utils::fs::glob_relative(cache_path_, cleanup_prefix + "*", entries, false, true);
+ std::vector<String> remove_entries;
+ for (size_t i = 0; i < entries.size(); i++)
+ {
+ const String& name = entries[i];
+ if (0 == name.find(cleanup_prefix))
+ {
+ if (0 == name.find(ctx_prefix))
+ continue; // skip current
+ remove_entries.push_back(name);
+ }
+ }
+ if (!remove_entries.empty())
+ {
+ CV_LOG_WARNING(NULL, (remove_entries.size() == 1
+ ? "Detected OpenCL cache directory for other version of OpenCL device."
+ : "Detected OpenCL cache directories for other versions of OpenCL device.")
+ << " We assume that these directories are obsolete after OpenCL runtime/drivers upgrade.");
+ CV_LOG_WARNING(NULL, "Trying to remove these directories...");
+ for (size_t i = 0; i < remove_entries.size(); i++)
+ {
+ CV_LOG_WARNING(NULL, "- " << remove_entries[i]);
+ }
+ CV_LOG_WARNING(NULL,"Note: You can disable this behavior via this option: CV_OPENCL_CACHE_CLEANUP=0");
+
+ for (size_t i = 0; i < remove_entries.size(); i++)
+ {
+ const String& name = remove_entries[i];
+ cv::String path = utils::fs::join(cache_path_, name);
+ try
+ {
+ utils::fs::remove_all(path);
+ CV_LOG_WARNING(NULL, "Removed: " << path);
+ }
+ catch (const cv::Exception& e)
+ {
+ CV_LOG_ERROR(NULL, "Exception during removal of obsolete OpenCL cache directory: " << path << std::endl << e.what());
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ CV_LOG_WARNING(NULL, "Can't check for obsolete OpenCL cache directories");
+ }
+ }
+ CV_LOG_VERBOSE(NULL, 1, " Result: " << (target_directory.empty() ? std::string("Failed") : target_directory));
return target_directory;
}
}
}
- std::string getPrefixString()
+ std::string& getPrefixString()
{
if (prefix.empty())
{
return prefix;
}
+ std::string& getPrefixBase()
+ {
+ if (prefix_base.empty())
+ {
+ const Device& d = devices[0];
+ prefix_base = d.vendorName() + "--" + d.name() + "--";
+ // sanitize chars
+ for (size_t i = 0; i < prefix_base.size(); i++)
+ {
+ char c = prefix_base[i];
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-'))
+ {
+ prefix_base[i] = '_';
+ }
+ }
+ }
+ return prefix_base;
+ }
+
IMPLEMENT_REFCOUNTABLE();
cl_context handle;
std::vector<Device> devices;
std::string prefix;
+ std::string prefix_base;
cv::Mutex program_cache_mutex;
typedef std::map<std::string, Program> phash_t;
{
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
OpenCLBinaryCacheConfigurator& config = OpenCLBinaryCacheConfigurator::getSingletonInstance();
- const std::string base_dir = config.prepareCacheDirectoryForContext(ctx.getImpl()->getPrefixString());
+ const std::string base_dir = config.prepareCacheDirectoryForContext(
+ ctx.getImpl()->getPrefixString(),
+ ctx.getImpl()->getPrefixBase()
+ );
const std::string fname = base_dir.empty() ? std::string() :
std::string(base_dir + src.getImpl()->module_.c_str() + "--" + src.getImpl()->name_ + "_" + src.getImpl()->codeHash_ + ".bin");
const cv::Ptr<utils::fs::FileLock> fileLock = config.cache_lock_; // can be empty
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
+#include <io.h>
+#include <stdio.h>
#elif defined __linux__ || defined __APPLE__
#include <sys/types.h>
#include <sys/stat.h>
namespace cv { namespace utils { namespace fs {
+#ifdef _WIN32
+static const char native_separator = '\\';
+#else
+static const char native_separator = '/';
+#endif
+
static inline
bool isPathSeparator(char c)
{
return c == '/' || c == '\\';
}
+cv::String join(const cv::String& base, const cv::String& path)
+{
+ if (base.empty())
+ return path;
+ if (path.empty())
+ return base;
+
+ bool baseSep = isPathSeparator(base[base.size() - 1]);
+ bool pathSep = isPathSeparator(path[0]);
+ String result;
+ if (baseSep && pathSep)
+ {
+ result = base + path.substr(1);
+ }
+ else if (!baseSep && !pathSep)
+ {
+ result = base + native_separator + path;
+ }
+ else
+ {
+ result = base + path;
+ }
+ return result;
+}
+
bool exists(const cv::String& path)
{
CV_INSTRUMENT_REGION()
#endif
}
+CV_EXPORTS void remove_all(const cv::String& path)
+{
+ if (!exists(path))
+ return;
+ if (isDirectory(path))
+ {
+ std::vector<String> entries;
+ utils::fs::glob(path, cv::String(), entries, false, true);
+ for (size_t i = 0; i < entries.size(); i++)
+ {
+ const String& e = entries[i];
+ remove_all(e);
+ }
+#ifdef _MSC_VER
+ bool result = _rmdir(path.c_str()) == 0;
+#else
+ bool result = rmdir(path.c_str()) == 0;
+#endif
+ if (!result)
+ {
+ CV_LOG_ERROR(NULL, "Can't remove directory: " << path);
+ }
+ }
+ else
+ {
+#ifdef _MSC_VER
+ bool result = _unlink(path.c_str()) == 0;
+#else
+ bool result = unlink(path.c_str()) == 0;
+#endif
+ if (!result)
+ {
+ CV_LOG_ERROR(NULL, "Can't remove file: " << path);
+ }
+ }
+}
+
+
cv::String getcwd()
{
CV_INSTRUMENT_REGION()
for (;;)
{
char last_char = path.empty() ? 0 : path[path.length() - 1];
- if (last_char == '/' || last_char == '\\')
+ if (isPathSeparator(last_char))
{
path = path.substr(0, path.length() - 1);
continue;
if (home_env && home_env[0] && utils::fs::isDirectory(home_env))
{
cv::String home_path = home_env;
- cv::String home_cache_path = home_path + "/.cache/";
+ cv::String home_cache_path = utils::fs::join(home_path, ".cache/");
if (utils::fs::isDirectory(home_cache_path))
{
default_cache_path = home_cache_path;
{
if (utils::fs::isDirectory(default_cache_path))
{
- default_cache_path += "/opencv/" CV_VERSION "/";
+ default_cache_path = utils::fs::join(default_cache_path, utils::fs::join("opencv", CV_VERSION));
if (sub_directory_name && sub_directory_name[0] != '\0')
- default_cache_path += cv::String(sub_directory_name) + "/";
+ default_cache_path = utils::fs::join(default_cache_path, cv::String(sub_directory_name) + native_separator);
if (!utils::fs::createDirectories(default_cache_path))
{
CV_LOG_DEBUG(NULL, "Can't create OpenCV cache sub-directory: " << default_cache_path);
{
if (!isPathSeparator(cache_path[cache_path.size() - 1]))
{
- cache_path += '/';
+ cache_path += native_separator;
}
}
return cache_path;