Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
e5d1790b
Commit
e5d1790b
authored
Nov 23, 2017
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10018 from alalek:ocl_binary_cache
parents
fed2a277
8e6280fc
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1471 additions
and
51 deletions
+1471
-51
ocl.hpp
modules/core/include/opencv2/core/ocl.hpp
+2
-0
filesystem.hpp
modules/core/include/opencv2/core/utils/filesystem.hpp
+38
-0
filesystem.private.hpp
...es/core/include/opencv2/core/utils/filesystem.private.hpp
+64
-0
lock.private.hpp
modules/core/include/opencv2/core/utils/lock.private.hpp
+119
-0
glob.cpp
modules/core/src/glob.cpp
+8
-0
ocl.cpp
modules/core/src/ocl.cpp
+795
-51
filesystem.cpp
modules/core/src/utils/filesystem.cpp
+445
-0
No files found.
modules/core/include/opencv2/core/ocl.hpp
View file @
e5d1790b
...
...
@@ -261,6 +261,8 @@ public:
void
setUseSVM
(
bool
enabled
);
struct
Impl
;
inline
Impl
*
getImpl
()
const
{
return
(
Impl
*
)
p
;
}
//protected:
Impl
*
p
;
};
...
...
modules/core/include/opencv2/core/utils/filesystem.hpp
0 → 100644
View file @
e5d1790b
// 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_FILESYSTEM_HPP
#define OPENCV_UTILS_FILESYSTEM_HPP
namespace
cv
{
namespace
utils
{
namespace
fs
{
CV_EXPORTS
bool
exists
(
const
cv
::
String
&
path
);
CV_EXPORTS
bool
isDirectory
(
const
cv
::
String
&
path
);
CV_EXPORTS
cv
::
String
getcwd
();
CV_EXPORTS
bool
createDirectory
(
const
cv
::
String
&
path
);
CV_EXPORTS
bool
createDirectories
(
const
cv
::
String
&
path
);
#ifdef __OPENCV_BUILD
// TODO
//CV_EXPORTS cv::String getTempDirectory();
/**
* @brief Returns directory to store OpenCV cache files
* Create sub-directory in common OpenCV cache directory if it doesn't exist.
* @param sub_directory_name name of sub-directory. NULL or "" value asks to return root cache directory.
* @param configuration_name optional name of configuration parameter name which overrides default behavior.
* @return Path to cache directory. Returns empty string if cache directories support is not available. Returns "disabled" if cache disabled by user.
*/
CV_EXPORTS
cv
::
String
getCacheDirectory
(
const
char
*
sub_directory_name
,
const
char
*
configuration_name
=
NULL
);
#endif
}}}
// namespace
#endif // OPENCV_UTILS_FILESYSTEM_HPP
modules/core/include/opencv2/core/utils/filesystem.private.hpp
0 → 100644
View file @
e5d1790b
// 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_FILESYSTEM_PRIVATE_HPP
#define OPENCV_UTILS_FILESYSTEM_PRIVATE_HPP
// TODO Move to CMake?
#ifndef OPENCV_HAVE_FILESYSTEM_SUPPORT
# if defined(__EMSCRIPTEN__) || defined(__native_client__)
/* no support */
# elif defined __ANDROID__ || defined __linux__ || defined _WIN32 || \
defined __FreeBSD__ || defined __bsdi__
# define OPENCV_HAVE_FILESYSTEM_SUPPORT 1
# elif defined(__APPLE__)
# include <TargetConditionals.h>
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX) || (!defined(TARGET_OS_OSX) && !TARGET_OS_IPHONE)
# define OPENCV_HAVE_FILESYSTEM_SUPPORT 1 // OSX only
# endif
# else
/* unknown */
# endif
# ifndef OPENCV_HAVE_FILESYSTEM_SUPPORT
# define OPENCV_HAVE_FILESYSTEM_SUPPORT 0
# endif
#endif
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
namespace
cv
{
namespace
utils
{
namespace
fs
{
/**
* File-based lock object.
*
* Provides interprocess synchronization mechanism.
* Platform dependent.
*
* Supports multiple readers / single writer access pattern (RW / readers–writer / shared-exclusive lock).
*
* File must exist.
* File can't be re-used (for example, I/O operations via std::fstream is not safe)
*/
class
CV_EXPORTS
FileLock
{
public
:
explicit
FileLock
(
const
char
*
fname
);
~
FileLock
();
void
lock
();
//< acquire exclusive (writer) lock
void
unlock
();
//< release exclusive (writer) lock
void
lock_shared
();
//< acquire sharable (reader) lock
void
unlock_shared
();
//< release sharable (reader) lock
struct
Impl
;
protected
:
Impl
*
pImpl
;
private
:
FileLock
(
const
FileLock
&
);
// disabled
FileLock
&
operator
=
(
const
FileLock
&
);
// disabled
};
}}}
// namespace
#endif
#endif // OPENCV_UTILS_FILESYSTEM_PRIVATE_HPP
modules/core/include/opencv2/core/utils/lock.private.hpp
0 → 100644
View file @
e5d1790b
// 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_LOCK_HPP
#define OPENCV_UTILS_LOCK_HPP
namespace
cv
{
namespace
utils
{
/** @brief A simple scoped lock (RAII-style locking for exclusive/write access).
*
* Emulate std::lock_guard (C++11), partially std::unique_lock (C++11),
*/
template
<
class
_Mutex
>
class
lock_guard
{
public
:
typedef
_Mutex
Mutex
;
explicit
inline
lock_guard
(
Mutex
&
m
)
:
mutex_
(
&
m
)
{
mutex_
->
lock
();
}
inline
~
lock_guard
()
{
if
(
mutex_
)
mutex_
->
unlock
();
}
inline
void
release
()
{
CV_DbgAssert
(
mutex_
);
mutex_
->
unlock
();
mutex_
=
NULL
;
}
private
:
Mutex
*
mutex_
;
private
:
lock_guard
(
const
lock_guard
&
);
// disabled
lock_guard
&
operator
=
(
const
lock_guard
&
);
// disabled
};
/** @brief A shared scoped lock (RAII-style locking for shared/reader access).
*
* Emulate boost::shared_lock_guard, subset of std::shared_lock (C++14),
*/
template
<
class
_Mutex
>
class
shared_lock_guard
{
public
:
typedef
_Mutex
Mutex
;
explicit
inline
shared_lock_guard
(
Mutex
&
m
)
:
mutex_
(
&
m
)
{
mutex_
->
lock_shared
();
}
inline
~
shared_lock_guard
()
{
if
(
mutex_
)
mutex_
->
unlock_shared
();
}
inline
void
release
()
{
CV_DbgAssert
(
mutex_
);
mutex_
->
unlock_shared
();
mutex_
=
NULL
;
}
protected
:
Mutex
*
mutex_
;
private
:
shared_lock_guard
(
const
shared_lock_guard
&
);
// disabled
shared_lock_guard
&
operator
=
(
const
shared_lock_guard
&
);
// disabled
};
/** @brief An optional simple scoped lock (RAII-style locking for exclusive/write access).
*
* Doesn't lock if mutex pointer is NULL.
*
* @sa lock_guard
*/
template
<
class
_Mutex
>
class
optional_lock_guard
{
public
:
typedef
_Mutex
Mutex
;
explicit
inline
optional_lock_guard
(
Mutex
*
m
)
:
mutex_
(
m
)
{
if
(
mutex_
)
mutex_
->
lock
();
}
inline
~
optional_lock_guard
()
{
if
(
mutex_
)
mutex_
->
unlock
();
}
private
:
Mutex
*
mutex_
;
private
:
optional_lock_guard
(
const
optional_lock_guard
&
);
// disabled
optional_lock_guard
&
operator
=
(
const
optional_lock_guard
&
);
// disabled
};
/** @brief An optional shared scoped lock (RAII-style locking for shared/reader access).
*
* Doesn't lock if mutex pointer is NULL.
*
* @sa shared_lock_guard
*/
template
<
class
_Mutex
>
class
optional_shared_lock_guard
{
public
:
typedef
_Mutex
Mutex
;
explicit
inline
optional_shared_lock_guard
(
Mutex
*
m
)
:
mutex_
(
m
)
{
if
(
mutex_
)
mutex_
->
lock_shared
();
}
inline
~
optional_shared_lock_guard
()
{
if
(
mutex_
)
mutex_
->
unlock_shared
();
}
protected
:
Mutex
*
mutex_
;
private
:
optional_shared_lock_guard
(
const
optional_shared_lock_guard
&
);
// disabled
optional_shared_lock_guard
&
operator
=
(
const
optional_shared_lock_guard
&
);
// disabled
};
}}
// namespace
#endif // OPENCV_UTILS_LOCK_HPP
modules/core/src/glob.cpp
View file @
e5d1790b
...
...
@@ -42,6 +42,8 @@
#include "precomp.hpp"
#include "opencv2/core/utils/filesystem.hpp"
#if defined _WIN32 || defined WINCE
# include <windows.h>
const
char
dir_separators
[]
=
"/
\\
"
;
...
...
@@ -169,6 +171,12 @@ static bool isDir(const cv::String& path, DIR* dir)
#endif
}
bool
cv
::
utils
::
fs
::
isDirectory
(
const
cv
::
String
&
path
)
{
CV_INSTRUMENT_REGION
()
return
isDir
(
path
,
NULL
);
}
static
bool
wildcmp
(
const
char
*
string
,
const
char
*
wild
)
{
// Based on wildcmp written by Jack Handy - <A href="mailto:jakkhandy@hotmail.com">jakkhandy@hotmail.com</A>
...
...
modules/core/src/ocl.cpp
View file @
e5d1790b
...
...
@@ -47,22 +47,31 @@
#include <string>
#include <sstream>
#include <iostream> // std::cerr
#include <fstream>
#if !(defined _MSC_VER) || (defined _MSC_VER && _MSC_VER > 1700)
#include <inttypes.h>
#endif
#include <opencv2/core/utils/configuration.private.hpp>
#include <opencv2/core/utils/logger.hpp>
#include "opencv2/core/ocl_genbase.hpp"
#include "opencl_kernels_core.hpp"
#define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0
#include "opencv2/core/utils/lock.private.hpp"
#include "opencv2/core/utils/filesystem.hpp"
#include "opencv2/core/utils/filesystem.private.hpp"
#define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0
#define CV_OPENCL_SHOW_RUN_KERNELS 0
#define CV_OPENCL_TRACE_CHECK 0
#define CV_OPENCL_SHOW_RUN_KERNELS 0
#define CV_OPENCL_TRACE_CHECK 0
#define CV_OPENCL_VALIDATE_BINARY_PROGRAMS 1
#define CV_OPENCL_SHOW_SVM_ERROR_LOG 1
#define CV_OPENCL_SHOW_SVM_LOG 0
#define CV_OPENCL_SHOW_SVM_ERROR_LOG
1
#define CV_OPENCL_SHOW_SVM_LOG
0
#include "opencv2/core/bufferpool.hpp"
#ifndef LOG_BUFFER_POOL
...
...
@@ -167,6 +176,16 @@ void traceOpenCLCheck(cl_int status, const char* message)
#define CV_OCL_DBG_CHECK(expr) do { cl_int __cl_result = (expr); CV_OCL_DBG_CHECK_RESULT(__cl_result, #expr); } while (0)
#endif
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
);
#if CV_OPENCL_VALIDATE_BINARY_PROGRAMS
static
const
bool
CV_OPENCL_VALIDATE_BINARY_PROGRAMS_VALUE
=
utils
::
getConfigurationParameterBool
(
"OPENCV_OPENCL_VALIDATE_BINARY_PROGRAMS"
,
false
);
#endif
struct
UMat2D
{
UMat2D
(
const
UMat
&
m
)
...
...
@@ -226,6 +245,486 @@ static uint64 crc64( const uchar* data, size_t size, uint64 crc0=0 )
return
~
crc
;
}
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
struct
OpenCLBinaryCacheConfigurator
{
cv
::
String
cache_path_
;
cv
::
String
cache_lock_filename_
;
cv
::
Ptr
<
utils
::
fs
::
FileLock
>
cache_lock_
;
typedef
std
::
map
<
std
::
string
,
std
::
string
>
ContextCacheType
;
ContextCacheType
prepared_contexts_
;
OpenCLBinaryCacheConfigurator
()
{
CV_LOG_DEBUG
(
NULL
,
"Initializing OpenCL cache configuration..."
);
if
(
!
CV_OPENCL_CACHE_ENABLE
)
{
CV_LOG_INFO
(
NULL
,
"OpenCL cache is disabled"
);
return
;
}
cache_path_
=
utils
::
fs
::
getCacheDirectory
(
"opencl_cache"
,
"OPENCV_OPENCL_CACHE_DIR"
);
if
(
cache_path_
.
empty
())
{
CV_LOG_INFO
(
NULL
,
"Specify OPENCV_OPENCL_CACHE_DIR configuration parameter to enable OpenCL cache"
);
}
do
{
try
{
if
(
cache_path_
.
empty
())
break
;
if
(
cache_path_
==
"disabled"
)
break
;
if
(
!
utils
::
fs
::
createDirectories
(
cache_path_
))
{
CV_LOG_DEBUG
(
NULL
,
"Can't use OpenCL cache directory: "
<<
cache_path_
);
clear
();
break
;
}
if
(
CV_OPENCL_CACHE_LOCK_ENABLE
)
{
cache_lock_filename_
=
cache_path_
+
".lock"
;
if
(
!
utils
::
fs
::
exists
(
cache_lock_filename_
))
{
CV_LOG_DEBUG
(
NULL
,
"Creating lock file... ("
<<
cache_lock_filename_
<<
")"
);
std
::
ofstream
lock_filename
(
cache_lock_filename_
.
c_str
(),
std
::
ios
::
out
);
if
(
!
lock_filename
.
is_open
())
{
CV_LOG_WARNING
(
NULL
,
"Can't create lock file for OpenCL program cache: "
<<
cache_lock_filename_
);
break
;
}
}
try
{
cache_lock_
=
makePtr
<
utils
::
fs
::
FileLock
>
(
cache_lock_filename_
.
c_str
());
CV_LOG_VERBOSE
(
NULL
,
0
,
"Checking cache lock... ("
<<
cache_lock_filename_
<<
")"
);
{
utils
::
shared_lock_guard
<
utils
::
fs
::
FileLock
>
lock
(
*
cache_lock_
);
}
CV_LOG_VERBOSE
(
NULL
,
0
,
"Checking cache lock... Done!"
);
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_LOG_WARNING
(
NULL
,
"Can't create OpenCL program cache lock: "
<<
cache_lock_filename_
<<
std
::
endl
<<
e
.
what
());
}
catch
(...)
{
CV_LOG_WARNING
(
NULL
,
"Can't create OpenCL program cache lock: "
<<
cache_lock_filename_
);
}
}
else
{
if
(
CV_OPENCL_CACHE_WRITE
)
{
CV_LOG_WARNING
(
NULL
,
"OpenCL cache lock is disabled while cache write is allowed "
"(not safe for multiprocess environment)"
);
}
else
{
CV_LOG_INFO
(
NULL
,
"OpenCL cache lock is disabled"
);
}
}
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_LOG_WARNING
(
NULL
,
"Can't prepare OpenCL program cache: "
<<
cache_path_
<<
std
::
endl
<<
e
.
what
());
clear
();
}
}
while
(
0
);
if
(
!
cache_path_
.
empty
())
{
if
(
cache_lock_
.
empty
()
&&
CV_OPENCL_CACHE_LOCK_ENABLE
)
{
CV_LOG_WARNING
(
NULL
,
"Initialized OpenCL cache directory, but interprocess synchronization lock is not available. "
"Consider to disable OpenCL cache: OPENCV_OPENCL_CACHE_DIR=disabled"
);
}
else
{
CV_LOG_INFO
(
NULL
,
"Successfully initialized OpenCL cache directory: "
<<
cache_path_
);
}
}
}
void
clear
()
{
cache_path_
.
clear
();
cache_lock_filename_
.
clear
();
cache_lock_
.
release
();
}
std
::
string
prepareCacheDirectoryForContext
(
const
std
::
string
&
ctx_prefix
)
{
if
(
cache_path_
.
empty
())
return
std
::
string
();
ContextCacheType
::
iterator
i
=
prepared_contexts_
.
find
(
ctx_prefix
);
if
(
i
!=
prepared_contexts_
.
end
())
return
i
->
second
;
CV_LOG_INFO
(
NULL
,
"Preparing OpenCL cache configuration for context: "
<<
ctx_prefix
);
std
::
string
target_directory
=
cache_path_
+
ctx_prefix
+
"/"
;
bool
result
=
utils
::
fs
::
isDirectory
(
target_directory
);
if
(
!
result
)
{
try
{
CV_LOG_VERBOSE
(
NULL
,
0
,
"Creating directory: "
<<
target_directory
);
if
(
utils
::
fs
::
createDirectories
(
target_directory
))
{
result
=
true
;
}
else
{
CV_LOG_WARNING
(
NULL
,
"Can't create directory: "
<<
target_directory
);
}
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_LOG_ERROR
(
NULL
,
"Can't create OpenCL program cache directory for context: "
<<
target_directory
<<
std
::
endl
<<
e
.
what
());
}
}
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
));
return
target_directory
;
}
static
OpenCLBinaryCacheConfigurator
&
getSingletonInstance
()
{
CV_SINGLETON_LAZY_INIT_REF
(
OpenCLBinaryCacheConfigurator
,
new
OpenCLBinaryCacheConfigurator
());
}
};
class
BinaryProgramFile
{
enum
{
MAX_ENTRIES
=
64
};
typedef
unsigned
int
uint32_t
;
struct
CV_DECL_ALIGNED
(
4
)
FileHeader
{
uint32_t
sourceSignatureSize
;
//char sourceSignature[];
};
struct
CV_DECL_ALIGNED
(
4
)
FileTable
{
uint32_t
numberOfEntries
;
//uint32_t firstEntryOffset[];
};
struct
CV_DECL_ALIGNED
(
4
)
FileEntry
{
uint32_t
nextEntryFileOffset
;
// 0 for the last entry in chain
uint32_t
keySize
;
uint32_t
dataSize
;
//char key[];
//char data[];
};
const
std
::
string
fileName_
;
const
char
*
const
sourceSignature_
;
const
size_t
sourceSignatureSize_
;
std
::
fstream
f
;
uint32_t
entryOffsets
[
MAX_ENTRIES
];
uint32_t
getHash
(
const
std
::
string
&
options
)
{
uint64
hash
=
crc64
((
const
uchar
*
)
options
.
c_str
(),
options
.
size
(),
0
);
return
hash
&
(
MAX_ENTRIES
-
1
);
}
inline
size_t
getFileSize
()
{
size_t
pos
=
(
size_t
)
f
.
tellg
();
f
.
seekg
(
0
,
std
::
fstream
::
end
);
size_t
fileSize
=
(
size_t
)
f
.
tellg
();
f
.
seekg
(
pos
,
std
::
fstream
::
beg
);
return
fileSize
;
}
inline
uint32_t
readUInt32
()
{
uint32_t
res
=
0
;
f
.
read
((
char
*
)
&
res
,
sizeof
(
uint32_t
));
CV_Assert
(
!
f
.
fail
());
return
res
;
}
inline
void
writeUInt32
(
const
uint32_t
value
)
{
uint32_t
v
=
value
;
f
.
write
((
char
*
)
&
v
,
sizeof
(
uint32_t
));
CV_Assert
(
!
f
.
fail
());
}
inline
void
seekReadAbsolute
(
size_t
pos
)
{
f
.
seekg
(
pos
,
std
::
fstream
::
beg
);
CV_Assert
(
!
f
.
fail
());
}
inline
void
seekReadRelative
(
size_t
pos
)
{
f
.
seekg
(
pos
,
std
::
fstream
::
cur
);
CV_Assert
(
!
f
.
fail
());
}
inline
void
seekWriteAbsolute
(
size_t
pos
)
{
f
.
seekp
(
pos
,
std
::
fstream
::
beg
);
CV_Assert
(
!
f
.
fail
());
}
void
clearFile
()
{
f
.
close
();
if
(
0
!=
remove
(
fileName_
.
c_str
()))
CV_LOG_ERROR
(
NULL
,
"Can't remove: "
<<
fileName_
);
return
;
}
public
:
BinaryProgramFile
(
const
std
::
string
&
fileName
,
const
char
*
sourceSignature
)
:
fileName_
(
fileName
),
sourceSignature_
(
sourceSignature
),
sourceSignatureSize_
(
sourceSignature_
?
strlen
(
sourceSignature_
)
:
0
)
{
CV_StaticAssert
(
sizeof
(
uint32_t
)
==
4
,
""
);
CV_Assert
(
sourceSignature_
!=
NULL
);
CV_Assert
(
sourceSignatureSize_
>
0
);
memset
(
entryOffsets
,
0
,
sizeof
(
entryOffsets
));
f
.
rdbuf
()
->
pubsetbuf
(
0
,
0
);
// disable buffering
f
.
open
(
fileName_
.
c_str
(),
std
::
ios
::
in
|
std
::
ios
::
out
|
std
::
ios
::
binary
);
if
(
f
.
is_open
()
&&
getFileSize
()
>
0
)
{
bool
isValid
=
false
;
try
{
uint32_t
fileSourceSignatureSize
=
readUInt32
();
if
(
fileSourceSignatureSize
==
sourceSignatureSize_
)
{
cv
::
AutoBuffer
<
char
>
fileSourceSignature
(
fileSourceSignatureSize
+
1
);
f
.
read
((
char
*
)
fileSourceSignature
,
fileSourceSignatureSize
);
if
(
f
.
eof
())
{
CV_LOG_ERROR
(
NULL
,
"Unexpected EOF"
);
}
else
if
(
memcmp
(
sourceSignature
,
(
const
char
*
)
fileSourceSignature
,
fileSourceSignatureSize
)
==
0
)
{
isValid
=
true
;
}
}
if
(
!
isValid
)
{
CV_LOG_ERROR
(
NULL
,
"Source code signature/hash mismatch (program source code has been changed/updated)"
);
}
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_LOG_ERROR
(
NULL
,
"Can't open binary program file: "
<<
fileName
<<
" : "
<<
e
.
what
());
}
catch
(...)
{
CV_LOG_ERROR
(
NULL
,
"Can't open binary program file: "
<<
fileName
<<
" : Unknown error"
);
}
if
(
!
isValid
)
{
clearFile
();
}
else
{
seekReadAbsolute
(
0
);
}
}
}
bool
read
(
const
std
::
string
&
key
,
std
::
vector
<
char
>&
buf
)
{
if
(
!
f
.
is_open
())
return
false
;
size_t
fileSize
=
getFileSize
();
if
(
fileSize
==
0
)
{
CV_LOG_ERROR
(
NULL
,
"Invalid file (empty): "
<<
fileName_
);
clearFile
();
return
false
;
}
seekReadAbsolute
(
0
);
// bypass FileHeader
uint32_t
fileSourceSignatureSize
=
readUInt32
();
CV_Assert
(
fileSourceSignatureSize
>
0
);
seekReadRelative
(
fileSourceSignatureSize
);
uint32_t
numberOfEntries
=
readUInt32
();
CV_Assert
(
numberOfEntries
>
0
);
if
(
numberOfEntries
!=
MAX_ENTRIES
)
{
CV_LOG_ERROR
(
NULL
,
"Invalid file: "
<<
fileName_
);
clearFile
();
return
false
;
}
f
.
read
((
char
*
)
&
entryOffsets
[
0
],
sizeof
(
entryOffsets
));
CV_Assert
(
!
f
.
fail
());
uint32_t
entryNum
=
getHash
(
key
);
uint32_t
entryOffset
=
entryOffsets
[
entryNum
];
FileEntry
entry
;
while
(
entryOffset
>
0
)
{
seekReadAbsolute
(
entryOffset
);
//CV_StaticAssert(sizeof(entry) == sizeof(uint32_t) * 3, "");
f
.
read
((
char
*
)
&
entry
,
sizeof
(
entry
));
CV_Assert
(
!
f
.
fail
());
cv
::
AutoBuffer
<
char
>
fileKey
(
entry
.
keySize
+
1
);
if
(
key
.
size
()
==
entry
.
keySize
)
{
if
(
entry
.
keySize
>
0
)
{
f
.
read
((
char
*
)
fileKey
,
entry
.
keySize
);
CV_Assert
(
!
f
.
fail
());
}
if
(
memcmp
((
const
char
*
)
fileKey
,
key
.
c_str
(),
entry
.
keySize
)
==
0
)
{
buf
.
resize
(
entry
.
dataSize
);
f
.
read
(
&
buf
[
0
],
entry
.
dataSize
);
CV_Assert
(
!
f
.
fail
());
seekReadAbsolute
(
0
);
CV_LOG_VERBOSE
(
NULL
,
0
,
"Read..."
);
return
true
;
}
}
if
(
entry
.
nextEntryFileOffset
==
0
)
break
;
entryOffset
=
entry
.
nextEntryFileOffset
;
}
return
false
;
}
bool
write
(
const
std
::
string
&
key
,
std
::
vector
<
char
>&
buf
)
{
if
(
!
f
.
is_open
())
{
f
.
open
(
fileName_
.
c_str
(),
std
::
ios
::
in
|
std
::
ios
::
out
|
std
::
ios
::
binary
);
if
(
!
f
.
is_open
())
{
f
.
open
(
fileName_
.
c_str
(),
std
::
ios
::
out
|
std
::
ios
::
binary
);
if
(
!
f
.
is_open
())
{
CV_LOG_ERROR
(
NULL
,
"Can't create file: "
<<
fileName_
);
return
false
;
}
}
}
size_t
fileSize
=
getFileSize
();
if
(
fileSize
==
0
)
{
// Write header
seekWriteAbsolute
(
0
);
writeUInt32
((
uint32_t
)
sourceSignatureSize_
);
f
.
write
(
sourceSignature_
,
sourceSignatureSize_
);
CV_Assert
(
!
f
.
fail
());
writeUInt32
(
MAX_ENTRIES
);
memset
(
entryOffsets
,
0
,
sizeof
(
entryOffsets
));
f
.
write
((
char
*
)
entryOffsets
,
sizeof
(
entryOffsets
));
CV_Assert
(
!
f
.
fail
());
f
.
flush
();
CV_Assert
(
!
f
.
fail
());
f
.
close
();
f
.
open
(
fileName_
.
c_str
(),
std
::
ios
::
in
|
std
::
ios
::
out
|
std
::
ios
::
binary
);
CV_Assert
(
f
.
is_open
());
fileSize
=
getFileSize
();
}
seekReadAbsolute
(
0
);
// bypass FileHeader
uint32_t
fileSourceSignatureSize
=
readUInt32
();
CV_Assert
(
fileSourceSignatureSize
==
sourceSignatureSize_
);
seekReadRelative
(
fileSourceSignatureSize
);
uint32_t
numberOfEntries
=
readUInt32
();
CV_Assert
(
numberOfEntries
>
0
);
if
(
numberOfEntries
!=
MAX_ENTRIES
)
{
CV_LOG_ERROR
(
NULL
,
"Invalid file: "
<<
fileName_
);
clearFile
();
return
false
;
}
size_t
tableEntriesOffset
=
(
size_t
)
f
.
tellg
();
f
.
read
((
char
*
)
&
entryOffsets
[
0
],
sizeof
(
entryOffsets
));
CV_Assert
(
!
f
.
fail
());
uint32_t
entryNum
=
getHash
(
key
);
uint32_t
entryOffset
=
entryOffsets
[
entryNum
];
FileEntry
entry
;
while
(
entryOffset
>
0
)
{
seekReadAbsolute
(
entryOffset
);
//CV_StaticAssert(sizeof(entry) == sizeof(uint32_t) * 3, "");
f
.
read
((
char
*
)
&
entry
,
sizeof
(
entry
));
CV_Assert
(
!
f
.
fail
());
cv
::
AutoBuffer
<
char
>
fileKey
(
entry
.
keySize
+
1
);
if
(
key
.
size
()
==
entry
.
keySize
)
{
if
(
entry
.
keySize
>
0
)
{
f
.
read
((
char
*
)
fileKey
,
entry
.
keySize
);
CV_Assert
(
!
f
.
fail
());
}
if
(
0
==
memcmp
((
const
char
*
)
fileKey
,
key
.
c_str
(),
entry
.
keySize
))
{
// duplicate
CV_LOG_VERBOSE
(
NULL
,
0
,
"Duplicate key ignored: "
<<
fileName_
);
return
false
;
}
}
if
(
entry
.
nextEntryFileOffset
==
0
)
break
;
entryOffset
=
entry
.
nextEntryFileOffset
;
}
seekReadAbsolute
(
0
);
if
(
entryOffset
>
0
)
{
seekWriteAbsolute
(
entryOffset
);
entry
.
nextEntryFileOffset
=
(
uint32_t
)
fileSize
;
f
.
write
((
char
*
)
&
entry
,
sizeof
(
entry
));
CV_Assert
(
!
f
.
fail
());
}
else
{
entryOffsets
[
entryNum
]
=
(
uint32_t
)
fileSize
;
seekWriteAbsolute
(
tableEntriesOffset
);
f
.
write
((
char
*
)
entryOffsets
,
sizeof
(
entryOffsets
));
CV_Assert
(
!
f
.
fail
());
}
seekWriteAbsolute
(
fileSize
);
entry
.
nextEntryFileOffset
=
0
;
entry
.
dataSize
=
(
uint32_t
)
buf
.
size
();
entry
.
keySize
=
(
uint32_t
)
key
.
size
();
f
.
write
((
char
*
)
&
entry
,
sizeof
(
entry
));
CV_Assert
(
!
f
.
fail
());
f
.
write
(
key
.
c_str
(),
entry
.
keySize
);
CV_Assert
(
!
f
.
fail
());
f
.
write
(
&
buf
[
0
],
entry
.
dataSize
);
CV_Assert
(
!
f
.
fail
());
f
.
flush
();
CV_Assert
(
!
f
.
fail
());
CV_LOG_VERBOSE
(
NULL
,
0
,
"Write... ("
<<
buf
.
size
()
<<
" bytes)"
);
return
true
;
}
};
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
bool
haveOpenCL
()
{
#ifdef HAVE_OPENCL
...
...
@@ -1470,11 +1969,32 @@ struct Context::Impl
}
}
std
::
string
getPrefixString
()
{
if
(
prefix
.
empty
())
{
const
Device
&
d
=
devices
[
0
];
prefix
=
d
.
vendorName
()
+
"--"
+
d
.
name
()
+
"--"
+
d
.
driverVersion
();
// sanitize chars
for
(
size_t
i
=
0
;
i
<
prefix
.
size
();
i
++
)
{
char
c
=
prefix
[
i
];
if
(
!
((
c
>=
'0'
&&
c
<=
'9'
)
||
(
c
>=
'a'
&&
c
<=
'z'
)
||
(
c
>=
'A'
&&
c
<=
'Z'
)
||
c
==
'_'
||
c
==
'-'
))
{
prefix
[
i
]
=
'_'
;
}
}
}
return
prefix
;
}
IMPLEMENT_REFCOUNTABLE
();
cl_context
handle
;
std
::
vector
<
Device
>
devices
;
std
::
string
prefix
;
cv
::
Mutex
program_cache_mutex
;
typedef
std
::
map
<
std
::
string
,
Program
>
phash_t
;
phash_t
phash
;
...
...
@@ -2700,13 +3220,141 @@ struct Program::Impl
handle
(
NULL
)
{
refcount
=
1
;
compile
(
Context
::
getDefault
(),
errmsg
);
const
Context
ctx
=
Context
::
getDefault
();
Device
device
=
ctx
.
device
(
0
);
if
(
device
.
isAMD
())
buildflags
+=
" -D AMD_DEVICE"
;
else
if
(
device
.
isIntel
())
buildflags
+=
" -D INTEL_DEVICE"
;
compile
(
ctx
,
errmsg
);
}
bool
compile
(
const
Context
&
ctx
,
String
&
errmsg
)
{
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
OpenCLBinaryCacheConfigurator
&
config
=
OpenCLBinaryCacheConfigurator
::
getSingletonInstance
();
const
std
::
string
base_dir
=
config
.
prepareCacheDirectoryForContext
(
ctx
.
getImpl
()
->
getPrefixString
());
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
const
String
&
hash_str
=
src
.
getImpl
()
->
codeHash_
;
if
(
!
fname
.
empty
()
&&
CV_OPENCL_CACHE_ENABLE
)
{
try
{
std
::
vector
<
char
>
binaryBuf
;
bool
res
=
false
;
{
cv
::
utils
::
optional_shared_lock_guard
<
cv
::
utils
::
fs
::
FileLock
>
lock_fs
(
fileLock
.
get
());
BinaryProgramFile
file
(
fname
,
hash_str
.
c_str
());
res
=
file
.
read
(
buildflags
,
binaryBuf
);
}
if
(
res
)
{
CV_Assert
(
!
binaryBuf
.
empty
());
bool
isLoaded
=
createFromBinary
(
ctx
,
binaryBuf
,
errmsg
);
if
(
isLoaded
)
return
true
;
}
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_UNUSED
(
e
);
CV_LOG_VERBOSE
(
NULL
,
0
,
"Can't load OpenCL binary: "
+
fname
<<
std
::
endl
<<
e
.
what
());
}
catch
(...)
{
CV_LOG_VERBOSE
(
NULL
,
0
,
"Can't load OpenCL binary: "
+
fname
);
}
}
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
CV_Assert
(
handle
==
NULL
);
CV_INSTRUMENT_REGION_OPENCL_COMPILE
(
cv
::
format
(
"Compile: %"
PRIx64
" options: %s"
,
src
.
hash
(),
buildflags
.
c_str
()).
c_str
());
if
(
!
buildFromSources
(
ctx
,
errmsg
))
{
return
true
;
}
CV_Assert
(
handle
!=
NULL
);
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
if
(
!
fname
.
empty
()
&&
CV_OPENCL_CACHE_WRITE
)
{
try
{
std
::
vector
<
char
>
binaryBuf
;
getProgramBinary
(
binaryBuf
);
{
cv
::
utils
::
optional_lock_guard
<
cv
::
utils
::
fs
::
FileLock
>
lock_fs
(
fileLock
.
get
());
BinaryProgramFile
file
(
fname
,
hash_str
.
c_str
());
file
.
write
(
buildflags
,
binaryBuf
);
}
}
catch
(
const
cv
::
Exception
&
e
)
{
CV_LOG_WARNING
(
NULL
,
"Can't save OpenCL binary into cache: "
+
fname
<<
std
::
endl
<<
e
.
what
());
}
catch
(...)
{
CV_LOG_WARNING
(
NULL
,
"Can't save OpenCL binary into cache: "
+
fname
);
}
}
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
#if CV_OPENCL_VALIDATE_BINARY_PROGRAMS
if
(
CV_OPENCL_VALIDATE_BINARY_PROGRAMS_VALUE
)
{
std
::
vector
<
char
>
binaryBuf
;
getProgramBinary
(
binaryBuf
);
if
(
!
binaryBuf
.
empty
())
{
CV_OCL_DBG_CHECK
(
clReleaseProgram
(
handle
));
handle
=
NULL
;
createFromBinary
(
ctx
,
binaryBuf
,
errmsg
);
}
}
#endif
return
handle
!=
NULL
;
}
void
dumpBuildLog_
(
cl_int
result
,
const
cl_device_id
*
deviceList
,
String
&
errmsg
)
{
AutoBuffer
<
char
,
4096
>
buffer
;
buffer
[
0
]
=
0
;
size_t
retsz
=
0
;
cl_int
log_retval
=
clGetProgramBuildInfo
(
handle
,
deviceList
[
0
],
CL_PROGRAM_BUILD_LOG
,
0
,
0
,
&
retsz
);
if
(
log_retval
==
CL_SUCCESS
&&
retsz
>
1
)
{
buffer
.
resize
(
retsz
+
16
);
log_retval
=
clGetProgramBuildInfo
(
handle
,
deviceList
[
0
],
CL_PROGRAM_BUILD_LOG
,
retsz
+
1
,
(
char
*
)
buffer
,
&
retsz
);
if
(
log_retval
==
CL_SUCCESS
)
{
if
(
retsz
<
buffer
.
size
())
buffer
[
retsz
]
=
0
;
else
buffer
[
buffer
.
size
()
-
1
]
=
0
;
}
else
{
buffer
[
0
]
=
0
;
}
}
errmsg
=
String
(
buffer
);
printf
(
"OpenCL program build log: %s/%s
\n
Status %d: %s
\n
%s
\n
%s
\n
"
,
src
.
getImpl
()
->
module_
.
c_str
(),
src
.
getImpl
()
->
name_
.
c_str
(),
result
,
getOpenCLErrorString
(
result
),
buildflags
.
c_str
(),
errmsg
.
c_str
());
fflush
(
stdout
);
}
bool
buildFromSources
(
const
Context
&
ctx
,
String
&
errmsg
)
{
CV_Assert
(
handle
==
NULL
);
CV_INSTRUMENT_REGION_OPENCL_COMPILE
(
cv
::
format
(
"Build OpenCL program: %s/%s %"
PRIx64
" options: %s"
,
src
.
getImpl
()
->
module_
.
c_str
(),
src
.
getImpl
()
->
name_
.
c_str
(),
src
.
hash
(),
buildflags
.
c_str
()).
c_str
());
CV_LOG_VERBOSE
(
NULL
,
0
,
"Compile... "
<<
src
.
getImpl
()
->
module_
.
c_str
()
<<
"/"
<<
src
.
getImpl
()
->
name_
.
c_str
());
const
String
&
srcstr
=
src
.
source
();
const
char
*
srcptr
=
srcstr
.
c_str
();
size_t
srclen
=
srcstr
.
size
();
...
...
@@ -2717,54 +3365,20 @@ struct Program::Impl
CV_Assert
(
handle
||
retval
!=
CL_SUCCESS
);
if
(
handle
&&
retval
==
CL_SUCCESS
)
{
int
i
,
n
=
(
int
)
ctx
.
ndevices
();
AutoBuffer
<
void
*>
deviceListBuf
(
n
+
1
);
void
**
deviceList
=
deviceListBuf
;
for
(
i
=
0
;
i
<
n
;
i
++
)
deviceList
[
i
]
=
ctx
.
device
(
i
).
ptr
();
Device
device
=
Device
::
getDefault
();
if
(
device
.
isAMD
())
buildflags
+=
" -D AMD_DEVICE"
;
else
if
(
device
.
isIntel
())
buildflags
+=
" -D INTEL_DEVICE"
;
retval
=
clBuildProgram
(
handle
,
n
,
(
const
cl_device_id
*
)
deviceList
,
buildflags
.
c_str
(),
0
,
0
);
size_t
n
=
ctx
.
ndevices
();
AutoBuffer
<
cl_device_id
,
4
>
deviceListBuf
(
n
+
1
);
cl_device_id
*
deviceList
=
deviceListBuf
;
for
(
size_t
i
=
0
;
i
<
n
;
i
++
)
{
deviceList
[
i
]
=
(
cl_device_id
)(
ctx
.
device
(
i
).
ptr
());
}
retval
=
clBuildProgram
(
handle
,
(
cl_uint
)
n
,
deviceList
,
buildflags
.
c_str
(),
0
,
0
);
#if !CV_OPENCL_ALWAYS_SHOW_BUILD_LOG
if
(
retval
!=
CL_SUCCESS
)
#endif
{
AutoBuffer
<
char
,
4096
>
buffer
;
buffer
[
0
]
=
0
;
size_t
retsz
=
0
;
cl_int
log_retval
=
clGetProgramBuildInfo
(
handle
,
(
cl_device_id
)
deviceList
[
0
],
CL_PROGRAM_BUILD_LOG
,
0
,
0
,
&
retsz
);
if
(
log_retval
==
CL_SUCCESS
&&
retsz
>
1
)
{
buffer
.
resize
(
retsz
+
16
);
log_retval
=
clGetProgramBuildInfo
(
handle
,
(
cl_device_id
)
deviceList
[
0
],
CL_PROGRAM_BUILD_LOG
,
retsz
+
1
,
(
char
*
)
buffer
,
&
retsz
);
if
(
log_retval
==
CL_SUCCESS
)
{
if
(
retsz
<
buffer
.
size
())
buffer
[
retsz
]
=
0
;
else
buffer
[
buffer
.
size
()
-
1
]
=
0
;
}
else
{
buffer
[
0
]
=
0
;
}
}
errmsg
=
String
(
buffer
);
printf
(
"OpenCL program build log: %s (%s)
\n
Status %d: %s
\n
%s
\n
%s
\n
"
,
src
.
getImpl
()
->
name_
.
c_str
(),
src
.
getImpl
()
->
module_
.
c_str
(),
retval
,
getOpenCLErrorString
(
retval
),
buildflags
.
c_str
(),
errmsg
.
c_str
());
fflush
(
stdout
);
dumpBuildLog_
(
retval
,
deviceList
,
errmsg
);
// don't remove "retval != CL_SUCCESS" condition here:
// it would break CV_OPENCL_ALWAYS_SHOW_BUILD_LOG mode
...
...
@@ -2774,6 +3388,7 @@ struct Program::Impl
handle
=
NULL
;
}
}
}
return
handle
!=
NULL
;
}
...
...
@@ -2830,6 +3445,135 @@ struct Program::Impl
return
String
((
const
char
*
)(
uchar
*
)
bufbuf
,
prefixlen
+
progsz
);
}
void
getProgramBinary
(
std
::
vector
<
char
>&
buf
)
{
CV_Assert
(
handle
);
size_t
sz
=
0
;
CV_OCL_CHECK
(
clGetProgramInfo
(
handle
,
CL_PROGRAM_BINARY_SIZES
,
sizeof
(
sz
),
&
sz
,
NULL
));
buf
.
resize
(
sz
);
uchar
*
ptr
=
(
uchar
*
)
&
buf
[
0
];
CV_OCL_CHECK
(
clGetProgramInfo
(
handle
,
CL_PROGRAM_BINARIES
,
sizeof
(
ptr
),
&
ptr
,
NULL
));
#if CV_OPENCL_VALIDATE_BINARY_PROGRAMS
if
(
CV_OPENCL_VALIDATE_BINARY_PROGRAMS_VALUE
)
{
CV_LOG_INFO
(
NULL
,
"OpenCL: query kernel names (compiled)..."
);
size_t
retsz
=
0
;
char
kernels_buffer
[
4096
]
=
{
0
};
cl_int
result
=
clGetProgramInfo
(
handle
,
CL_PROGRAM_KERNEL_NAMES
,
sizeof
(
kernels_buffer
),
&
kernels_buffer
[
0
],
&
retsz
);
if
(
retsz
<
sizeof
(
kernels_buffer
))
kernels_buffer
[
retsz
]
=
0
;
else
kernels_buffer
[
0
]
=
0
;
CV_LOG_INFO
(
NULL
,
result
<<
": Kernels='"
<<
kernels_buffer
<<
"'"
);
}
#endif
}
bool
createFromBinary
(
const
Context
&
ctx
,
const
std
::
vector
<
char
>&
buf
,
String
&
errmsg
)
{
CV_Assert
(
handle
==
NULL
);
CV_INSTRUMENT_REGION_OPENCL_COMPILE
(
"Load OpenCL program"
);
CV_LOG_VERBOSE
(
NULL
,
0
,
"Load from binary... "
<<
src
.
getImpl
()
->
module_
.
c_str
()
<<
"/"
<<
src
.
getImpl
()
->
name_
.
c_str
());
const
uchar
*
binaryPtr
=
(
uchar
*
)
&
buf
[
0
];
size_t
binarySize
=
buf
.
size
();
CV_Assert
(
binarySize
>
0
);
size_t
ndevices
=
(
int
)
ctx
.
ndevices
();
AutoBuffer
<
cl_device_id
>
devices_
(
ndevices
);
AutoBuffer
<
const
uchar
*>
binaryPtrs_
(
ndevices
);
AutoBuffer
<
size_t
>
binarySizes_
(
ndevices
);
cl_device_id
*
devices
=
devices_
;
const
uchar
**
binaryPtrs
=
binaryPtrs_
;
size_t
*
binarySizes
=
binarySizes_
;
for
(
size_t
i
=
0
;
i
<
ndevices
;
i
++
)
{
devices
[
i
]
=
(
cl_device_id
)
ctx
.
device
(
i
).
ptr
();
binaryPtrs
[
i
]
=
binaryPtr
;
binarySizes
[
i
]
=
binarySize
;
}
cl_int
result
=
0
;
handle
=
clCreateProgramWithBinary
((
cl_context
)
ctx
.
ptr
(),
(
cl_uint
)
ndevices
,
(
cl_device_id
*
)
devices_
,
binarySizes
,
binaryPtrs
,
NULL
,
&
result
);
if
(
result
!=
CL_SUCCESS
)
{
CV_LOG_ERROR
(
NULL
,
CV_OCL_API_ERROR_MSG
(
result
,
"clCreateProgramWithBinary"
));
if
(
handle
)
{
CV_OCL_DBG_CHECK
(
clReleaseProgram
(
handle
));
handle
=
NULL
;
}
}
if
(
!
handle
)
return
false
;
cl_build_status
build_status
=
CL_BUILD_NONE
;
size_t
retsz
=
0
;
CV_OCL_DBG_CHECK
(
result
=
clGetProgramBuildInfo
(
handle
,
devices
[
0
],
CL_PROGRAM_BUILD_STATUS
,
sizeof
(
build_status
),
&
build_status
,
&
retsz
));
if
(
result
==
CL_SUCCESS
&&
build_status
==
CL_BUILD_SUCCESS
)
{
CV_LOG_VERBOSE
(
NULL
,
0
,
"clGetProgramBuildInfo() pre-check returns CL_BUILD_SUCCESS. Skip clBuildProgram() call"
);
}
else
{
result
=
clBuildProgram
(
handle
,
(
cl_uint
)
ndevices
,
(
cl_device_id
*
)
devices_
,
buildflags
.
c_str
(),
0
,
0
);
CV_OCL_DBG_CHECK_RESULT
(
result
,
cv
::
format
(
"clBuildProgram(binary: %s/%s)"
,
src
.
getImpl
()
->
module_
.
c_str
(),
src
.
getImpl
()
->
name_
.
c_str
()).
c_str
());
if
(
result
!=
CL_SUCCESS
)
{
dumpBuildLog_
(
result
,
devices
,
errmsg
);
if
(
handle
)
{
CV_OCL_DBG_CHECK
(
clReleaseProgram
(
handle
));
handle
=
NULL
;
}
return
false
;
}
}
if
(
build_status
!=
CL_BUILD_SUCCESS
)
{
CV_OCL_DBG_CHECK
(
result
=
clGetProgramBuildInfo
(
handle
,
devices
[
0
],
CL_PROGRAM_BUILD_STATUS
,
sizeof
(
build_status
),
&
build_status
,
&
retsz
));
if
(
result
==
CL_SUCCESS
)
{
if
(
build_status
==
CL_BUILD_SUCCESS
)
{
return
true
;
}
else
{
CV_LOG_WARNING
(
NULL
,
"clGetProgramBuildInfo() returns "
<<
build_status
);
return
false
;
}
}
else
{
CV_LOG_ERROR
(
NULL
,
CV_OCL_API_ERROR_MSG
(
result
,
"clGetProgramBuildInfo()"
));
if
(
handle
)
{
CV_OCL_DBG_CHECK
(
clReleaseProgram
(
handle
));
handle
=
NULL
;
}
}
}
#if CV_OPENCL_VALIDATE_BINARY_PROGRAMS
if
(
handle
&&
CV_OPENCL_VALIDATE_BINARY_PROGRAMS_VALUE
)
{
CV_LOG_INFO
(
NULL
,
"OpenCL: query kernel names (binary)..."
);
retsz
=
0
;
char
kernels_buffer
[
4096
]
=
{
0
};
result
=
clGetProgramInfo
(
handle
,
CL_PROGRAM_KERNEL_NAMES
,
sizeof
(
kernels_buffer
),
&
kernels_buffer
[
0
],
&
retsz
);
if
(
retsz
<
sizeof
(
kernels_buffer
))
kernels_buffer
[
retsz
]
=
0
;
else
kernels_buffer
[
0
]
=
0
;
CV_LOG_INFO
(
NULL
,
result
<<
": Kernels='"
<<
kernels_buffer
<<
"'"
);
}
#endif
return
handle
!=
NULL
;
}
~
Impl
()
{
if
(
handle
)
...
...
modules/core/src/utils/filesystem.cpp
0 → 100644
View file @
e5d1790b
// 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"
#include <opencv2/core/utils/configuration.private.hpp>
#include <opencv2/core/utils/logger.hpp>
#include "opencv2/core/utils/filesystem.private.hpp"
#include "opencv2/core/utils/filesystem.hpp"
//#define DEBUG_FS_UTILS
#ifdef DEBUG_FS_UTILS
#include <iostream>
#define DBG(...) __VA_ARGS__
#else
#define DBG(...)
#endif
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <direct.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#elif defined __linux__ || defined __APPLE__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#endif
namespace
cv
{
namespace
utils
{
namespace
fs
{
static
inline
bool
isPathSeparator
(
char
c
)
{
return
c
==
'/'
||
c
==
'\\'
;
}
bool
exists
(
const
cv
::
String
&
path
)
{
CV_INSTRUMENT_REGION
()
#if defined _WIN32 || defined WINCE
BOOL
status
=
TRUE
;
{
WIN32_FILE_ATTRIBUTE_DATA
all_attrs
;
#ifdef WINRT
wchar_t
wpath
[
MAX_PATH
];
size_t
copied
=
mbstowcs
(
wpath
,
path
.
c_str
(),
MAX_PATH
);
CV_Assert
((
copied
!=
MAX_PATH
)
&&
(
copied
!=
(
size_t
)
-
1
));
status
=
::
GetFileAttributesExW
(
wpath
,
GetFileExInfoStandard
,
&
all_attrs
);
#else
status
=
::
GetFileAttributesExA
(
path
.
c_str
(),
GetFileExInfoStandard
,
&
all_attrs
);
#endif
}
return
!!
status
;
#else
struct
stat
stat_buf
;
return
(
0
==
stat
(
path
.
c_str
(),
&
stat_buf
));
#endif
}
cv
::
String
getcwd
()
{
CV_INSTRUMENT_REGION
()
cv
::
AutoBuffer
<
char
,
4096
>
buf
;
#if defined WIN32 || defined _WIN32 || defined WINCE
#ifdef WINRT
return
cv
::
String
();
#else
DWORD
sz
=
GetCurrentDirectoryA
(
0
,
NULL
);
buf
.
allocate
((
size_t
)
sz
);
sz
=
GetCurrentDirectoryA
((
DWORD
)
buf
.
size
(),
(
char
*
)
buf
);
return
cv
::
String
((
char
*
)
buf
,
(
size_t
)
sz
);
#endif
#elif defined __linux__ || defined __APPLE__
for
(;;)
{
char
*
p
=
::
getcwd
((
char
*
)
buf
,
buf
.
size
());
if
(
p
==
NULL
)
{
if
(
errno
==
ERANGE
)
{
buf
.
allocate
(
buf
.
size
()
*
2
);
continue
;
}
return
cv
::
String
();
}
break
;
}
return
cv
::
String
((
char
*
)
buf
,
(
size_t
)
strlen
((
char
*
)
buf
));
#else
return
cv
::
String
();
#endif
}
bool
createDirectory
(
const
cv
::
String
&
path
)
{
CV_INSTRUMENT_REGION
()
#if defined WIN32 || defined _WIN32 || defined WINCE
#ifdef WINRT
wchar_t
wpath
[
MAX_PATH
];
size_t
copied
=
mbstowcs
(
wpath
,
path
.
c_str
(),
MAX_PATH
);
CV_Assert
((
copied
!=
MAX_PATH
)
&&
(
copied
!=
(
size_t
)
-
1
));
int
result
=
CreateDirectoryA
(
wpath
,
NULL
)
?
0
:
-
1
;
#else
int
result
=
_mkdir
(
path
.
c_str
());
#endif
#elif defined __linux__ || defined __APPLE__
int
result
=
mkdir
(
path
.
c_str
(),
0777
);
#else
int
result
=
-
1
;
#endif
if
(
result
==
-
1
)
{
return
isDirectory
(
path
);
}
return
true
;
}
bool
createDirectories
(
const
cv
::
String
&
path_
)
{
cv
::
String
path
=
path_
;
for
(;;)
{
char
last_char
=
path
.
empty
()
?
0
:
path
[
path
.
length
()
-
1
];
if
(
last_char
==
'/'
||
last_char
==
'\\'
)
{
path
=
path
.
substr
(
0
,
path
.
length
()
-
1
);
continue
;
}
break
;
}
if
(
path
.
empty
()
||
path
==
"./"
||
path
==
".
\\
"
||
path
==
"."
)
return
true
;
if
(
isDirectory
(
path
))
return
true
;
size_t
pos
=
path
.
rfind
(
'/'
);
if
(
pos
==
cv
::
String
::
npos
)
pos
=
path
.
rfind
(
'\\'
);
if
(
pos
!=
cv
::
String
::
npos
)
{
cv
::
String
parent_directory
=
path
.
substr
(
0
,
pos
);
if
(
!
parent_directory
.
empty
())
{
if
(
!
createDirectories
(
parent_directory
))
return
false
;
}
}
return
createDirectory
(
path
);
}
#ifdef _WIN32
struct
FileLock
::
Impl
{
Impl
(
const
char
*
fname
)
{
// http://support.microsoft.com/kb/316609
int
numRetries
=
5
;
do
{
handle
=
::
CreateFileA
(
fname
,
GENERIC_READ
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
,
NULL
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
if
(
INVALID_HANDLE_VALUE
==
handle
)
{
if
(
ERROR_SHARING_VIOLATION
==
GetLastError
())
{
numRetries
--
;
Sleep
(
250
);
continue
;
}
else
{
CV_ErrorNoReturn_
(
Error
::
StsAssert
,
(
"Can't open lock file: %s"
,
fname
));
}
}
break
;
}
while
(
numRetries
>
0
);
}
~
Impl
()
{
if
(
INVALID_HANDLE_VALUE
!=
handle
)
{
::
CloseHandle
(
handle
);
}
}
bool
lock
()
{
OVERLAPPED
overlapped
;
std
::
memset
(
&
overlapped
,
0
,
sizeof
(
overlapped
));
return
!!::
LockFileEx
(
handle
,
LOCKFILE_EXCLUSIVE_LOCK
,
0
,
MAXDWORD
,
MAXDWORD
,
&
overlapped
);
}
bool
unlock
()
{
OVERLAPPED
overlapped
;
std
::
memset
(
&
overlapped
,
0
,
sizeof
(
overlapped
));
return
!!::
UnlockFileEx
(
handle
,
0
,
MAXDWORD
,
MAXDWORD
,
&
overlapped
);
}
bool
lock_shared
()
{
OVERLAPPED
overlapped
;
std
::
memset
(
&
overlapped
,
0
,
sizeof
(
overlapped
));
return
!!::
LockFileEx
(
handle
,
0
,
0
,
MAXDWORD
,
MAXDWORD
,
&
overlapped
);
}
bool
unlock_shared
()
{
return
unlock
();
}
HANDLE
handle
;
private
:
Impl
(
const
Impl
&
);
// disabled
Impl
&
operator
=
(
const
Impl
&
);
// disabled
};
#elif defined __linux__ || defined __APPLE__
struct
FileLock
::
Impl
{
Impl
(
const
char
*
fname
)
{
handle
=
::
open
(
fname
,
O_RDWR
);
CV_Assert
(
handle
!=
-
1
);
}
~
Impl
()
{
if
(
handle
>=
0
)
::
close
(
handle
);
}
bool
lock
()
{
struct
::
flock
l
;
std
::
memset
(
&
l
,
0
,
sizeof
(
l
));
l
.
l_type
=
F_WRLCK
;
l
.
l_whence
=
SEEK_SET
;
l
.
l_start
=
0
;
l
.
l_len
=
0
;
DBG
(
std
::
cout
<<
"Lock..."
<<
std
::
endl
);
bool
res
=
-
1
!=
::
fcntl
(
handle
,
F_SETLKW
,
&
l
);
return
res
;
}
bool
unlock
()
{
struct
::
flock
l
;
std
::
memset
(
&
l
,
0
,
sizeof
(
l
));
l
.
l_type
=
F_UNLCK
;
l
.
l_whence
=
SEEK_SET
;
l
.
l_start
=
0
;
l
.
l_len
=
0
;
DBG
(
std
::
cout
<<
"Unlock..."
<<
std
::
endl
);
bool
res
=
-
1
!=
::
fcntl
(
handle
,
F_SETLK
,
&
l
);
return
res
;
}
bool
lock_shared
()
{
struct
::
flock
l
;
std
::
memset
(
&
l
,
0
,
sizeof
(
l
));
l
.
l_type
=
F_RDLCK
;
l
.
l_whence
=
SEEK_SET
;
l
.
l_start
=
0
;
l
.
l_len
=
0
;
DBG
(
std
::
cout
<<
"Lock read..."
<<
std
::
endl
);
bool
res
=
-
1
!=
::
fcntl
(
handle
,
F_SETLKW
,
&
l
);
return
res
;
}
bool
unlock_shared
()
{
return
unlock
();
}
int
handle
;
private
:
Impl
(
const
Impl
&
);
// disabled
Impl
&
operator
=
(
const
Impl
&
);
// disabled
};
#endif
FileLock
::
FileLock
(
const
char
*
fname
)
:
pImpl
(
new
Impl
(
fname
))
{
// nothing
}
FileLock
::~
FileLock
()
{
delete
pImpl
;
pImpl
=
NULL
;
}
void
FileLock
::
lock
()
{
CV_Assert
(
pImpl
->
lock
());
}
void
FileLock
::
unlock
()
{
CV_Assert
(
pImpl
->
unlock
());
}
void
FileLock
::
lock_shared
()
{
CV_Assert
(
pImpl
->
lock_shared
());
}
void
FileLock
::
unlock_shared
()
{
CV_Assert
(
pImpl
->
unlock_shared
());
}
cv
::
String
getCacheDirectory
(
const
char
*
sub_directory_name
,
const
char
*
configuration_name
)
{
String
cache_path
;
if
(
configuration_name
)
{
cache_path
=
utils
::
getConfigurationParameterString
(
configuration_name
,
""
);
}
if
(
cache_path
.
empty
())
{
cv
::
String
default_cache_path
;
#ifdef _WIN32
char
tmp_path_buf
[
MAX_PATH
+
1
]
=
{
0
};
DWORD
res
=
GetTempPath
(
MAX_PATH
,
tmp_path_buf
);
if
(
res
>
0
&&
res
<=
MAX_PATH
)
{
default_cache_path
=
tmp_path_buf
;
}
#elif defined __ANDROID__
// no defaults
#elif defined __APPLE__
const
char
*
tmpdir_env
=
getenv
(
"TMPDIR"
);
if
(
tmpdir_env
&&
utils
::
fs
::
isDirectory
(
tmpdir_env
))
{
default_cache_path
=
tmpdir_env
;
}
else
{
default_cache_path
=
"/tmp/"
;
CV_LOG_WARNING
(
NULL
,
"Using world accessible cache directory. This may be not secure: "
<<
default_cache_path
);
}
#elif defined __linux__
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
if
(
default_cache_path
.
empty
())
{
const
char
*
xdg_cache_env
=
getenv
(
"XDG_CACHE_HOME"
);
if
(
xdg_cache_env
&&
xdg_cache_env
[
0
]
&&
utils
::
fs
::
isDirectory
(
xdg_cache_env
))
{
default_cache_path
=
xdg_cache_env
;
}
}
if
(
default_cache_path
.
empty
())
{
const
char
*
home_env
=
getenv
(
"HOME"
);
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/"
;
if
(
utils
::
fs
::
isDirectory
(
home_cache_path
))
{
default_cache_path
=
home_cache_path
;
}
}
}
if
(
default_cache_path
.
empty
())
{
const
char
*
temp_path
=
"/var/tmp/"
;
if
(
utils
::
fs
::
isDirectory
(
temp_path
))
{
default_cache_path
=
temp_path
;
CV_LOG_WARNING
(
NULL
,
"Using world accessible cache directory. This may be not secure: "
<<
default_cache_path
);
}
}
if
(
default_cache_path
.
empty
())
{
default_cache_path
=
"/tmp/"
;
CV_LOG_WARNING
(
NULL
,
"Using world accessible cache directory. This may be not secure: "
<<
default_cache_path
);
}
#else
// no defaults
#endif
CV_LOG_VERBOSE
(
NULL
,
0
,
"default_cache_path = "
<<
default_cache_path
);
if
(
!
default_cache_path
.
empty
())
{
if
(
utils
::
fs
::
isDirectory
(
default_cache_path
))
{
default_cache_path
+=
"/opencv/"
CV_VERSION
"/"
;
if
(
sub_directory_name
&&
sub_directory_name
[
0
]
!=
'\0'
)
default_cache_path
+=
cv
::
String
(
sub_directory_name
)
+
"/"
;
if
(
!
utils
::
fs
::
createDirectories
(
default_cache_path
))
{
CV_LOG_DEBUG
(
NULL
,
"Can't create OpenCV cache sub-directory: "
<<
default_cache_path
);
}
else
{
cache_path
=
default_cache_path
;
}
}
else
{
CV_LOG_INFO
(
NULL
,
"Can't find default cache directory (does it exist?): "
<<
default_cache_path
);
}
}
else
{
CV_LOG_DEBUG
(
NULL
,
"OpenCV has no support to discover default cache directory on the current platform"
);
}
}
else
{
if
(
cache_path
==
"disabled"
)
return
cache_path
;
if
(
!
isDirectory
(
cache_path
))
{
CV_LOG_WARNING
(
NULL
,
"Specified non-existed directory, creating OpenCV sub-directory for caching purposes: "
<<
cache_path
);
if
(
!
createDirectories
(
cache_path
))
{
CV_LOG_ERROR
(
NULL
,
"Can't create OpenCV cache sub-directory: "
<<
cache_path
);
cache_path
.
clear
();
}
}
}
CV_Assert
(
cache_path
.
empty
()
||
utils
::
fs
::
isDirectory
(
cache_path
));
if
(
!
cache_path
.
empty
())
{
if
(
!
isPathSeparator
(
cache_path
[
cache_path
.
size
()
-
1
]))
{
cache_path
+=
'/'
;
}
}
return
cache_path
;
}
}}}
// namespace
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment