Commit 1e869c5e authored by Maksim Shabunin's avatar Maksim Shabunin

ts: refactor run.py script

Conflicts:
	modules/ts/misc/run.py
parent 4552ca98
#!/usr/bin/env python
import sys, os, platform, xml, re, tempfile, glob, datetime, getpass, shutil
from optparse import OptionParser
from subprocess import Popen, PIPE
hostos = os.name # 'nt', 'posix'
hostmachine = platform.machine() # 'x86', 'AMD64', 'x86_64'
errorCode = 0
SIMD_DETECTION_PROGRAM="""
#if __SSE5__
# error SSE5
#endif
#if __AVX2__
# error AVX2
#endif
#if __AVX__
# error AVX
#endif
#if __SSE4_2__
# error SSE4.2
#endif
#if __SSE4_1__
# error SSE4.1
#endif
#if __SSSE3__
# error SSSE3
#endif
#if __SSE3__
# error SSE3
#endif
#if __AES__
# error AES
#endif
#if __SSE2__
# error SSE2
#endif
#if __SSE__
# error SSE
#endif
#if __3dNOW__
# error 3dNOW
#endif
#if __MMX__
# error MMX
#endif
#if __ARM_NEON__ || __ARM_NEON
# error NEON
#endif
#error NOSIMD
"""
parse_patterns = (
{'name': "has_perf_tests", 'default': "OFF", 'pattern': re.compile("^BUILD_PERF_TESTS:BOOL=(ON)$")},
{'name': "has_accuracy_tests", 'default': "OFF", 'pattern': re.compile("^BUILD_TESTS:BOOL=(ON)$")},
{'name': "cmake_home", 'default': None, 'pattern': re.compile("^CMAKE_HOME_DIRECTORY:INTERNAL=(.+)$")},
{'name': "opencv_home", 'default': None, 'pattern': re.compile("^OpenCV_SOURCE_DIR:STATIC=(.+)$")},
{'name': "tests_dir", 'default': None, 'pattern': re.compile("^EXECUTABLE_OUTPUT_PATH:PATH=(.+)$")},
{'name': "build_type", 'default': "Release", 'pattern': re.compile("^CMAKE_BUILD_TYPE:STRING=(.*)$")},
{'name': "svnversion_path", 'default': None, 'pattern': re.compile("^SVNVERSION_PATH:FILEPATH=(.*)$")},
{'name': "git_executable", 'default': None, 'pattern': re.compile("^GIT_EXECUTABLE:FILEPATH=(.*)$")},
{'name': "cxx_flags", 'default': "", 'pattern': re.compile("^CMAKE_CXX_FLAGS:STRING=(.*)$")},
{'name': "cxx_flags_debug", 'default': "", 'pattern': re.compile("^CMAKE_CXX_FLAGS_DEBUG:STRING=(.*)$")},
{'name': "cxx_flags_release", 'default': "", 'pattern': re.compile("^CMAKE_CXX_FLAGS_RELEASE:STRING=(.*)$")},
{'name': "opencv_cxx_flags", 'default': "", 'pattern': re.compile("^OPENCV_EXTRA_C_FLAGS:INTERNAL=(.*)$")},
{'name': "opencv_cxx_flags_debug", 'default': "", 'pattern': re.compile("^OPENCV_EXTRA_C_FLAGS_DEBUG:INTERNAL=(.*)$")},
{'name': "opencv_cxx_flags_release", 'default': "", 'pattern': re.compile("^OPENCV_EXTRA_C_FLAGS_RELEASE:INTERNAL=(.*)$")},
{'name': "cxx_flags_android", 'default': None, 'pattern': re.compile("^ANDROID_CXX_FLAGS:INTERNAL=(.*)$")},
{'name': "ndk_path", 'default': None, 'pattern': re.compile("^(?:ANDROID_NDK|ANDROID_STANDALONE_TOOLCHAIN)?:PATH=(.*)$")},
{'name': "android_abi", 'default': None, 'pattern': re.compile("^ANDROID_ABI:STRING=(.*)$")},
{'name': "android_executable", 'default': None, 'pattern': re.compile("^ANDROID_EXECUTABLE:FILEPATH=(.*android.*)$")},
{'name': "ant_executable", 'default': None, 'pattern': re.compile("^ANT_EXECUTABLE:FILEPATH=(.*ant.*)$")},
{'name': "java_test_binary_dir", 'default': None, 'pattern': re.compile("^opencv_test_java_BINARY_DIR:STATIC=(.*)$")},
{'name': "is_x64", 'default': "OFF", 'pattern': re.compile("^CUDA_64_BIT_DEVICE_CODE:BOOL=(ON)$")},#ugly(
{'name': "cmake_generator", 'default': None, 'pattern': re.compile("^CMAKE_GENERATOR:INTERNAL=(.+)$")},
{'name': "cxx_compiler", 'default': None, 'pattern': re.compile("^CMAKE_CXX_COMPILER:FILEPATH=(.+)$")},
{'name': "cxx_compiler_arg1", 'default': None, 'pattern': re.compile("^CMAKE_CXX_COMPILER_ARG1:[A-Z]+=(.+)$")},
{'name': "with_cuda", 'default': "OFF", 'pattern': re.compile("^WITH_CUDA:BOOL=(ON)$")},
{'name': "cuda_library", 'default': None, 'pattern': re.compile("^CUDA_CUDA_LIBRARY:FILEPATH=(.+)$")},
{'name': "core_dependencies", 'default': None, 'pattern': re.compile("^opencv_core_LIB_DEPENDS:STATIC=(.+)$")},
)
def query_yes_no(stdout, question, default="yes"):
valid = {"yes":True, "y":True, "ye":True, "no":False, "n":False}
if default == None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
stdout.write(os.linesep + question + prompt)
choice = raw_input().lower()
if default is not None and choice == '':
return valid[default]
elif choice in valid:
return valid[choice]
else:
stdout.write("Please respond with 'yes' or 'no' "\
"(or 'y' or 'n').\n")
def getRunningProcessExePathByName_win32(name):
from ctypes import windll, POINTER, pointer, Structure, sizeof
from ctypes import c_long , c_int , c_uint , c_char , c_ubyte , c_char_p , c_void_p
class PROCESSENTRY32(Structure):
_fields_ = [ ( 'dwSize' , c_uint ) ,
( 'cntUsage' , c_uint) ,
( 'th32ProcessID' , c_uint) ,
( 'th32DefaultHeapID' , c_uint) ,
( 'th32ModuleID' , c_uint) ,
( 'cntThreads' , c_uint) ,
( 'th32ParentProcessID' , c_uint) ,
( 'pcPriClassBase' , c_long) ,
( 'dwFlags' , c_uint) ,
( 'szExeFile' , c_char * 260 ) ,
( 'th32MemoryBase' , c_long) ,
( 'th32AccessKey' , c_long ) ]
class MODULEENTRY32(Structure):
_fields_ = [ ( 'dwSize' , c_long ) ,
( 'th32ModuleID' , c_long ),
( 'th32ProcessID' , c_long ),
( 'GlblcntUsage' , c_long ),
( 'ProccntUsage' , c_long ) ,
( 'modBaseAddr' , c_long ) ,
( 'modBaseSize' , c_long ) ,
( 'hModule' , c_void_p ) ,
( 'szModule' , c_char * 256 ),
( 'szExePath' , c_char * 260 ) ]
TH32CS_SNAPPROCESS = 2
TH32CS_SNAPMODULE = 0x00000008
## CreateToolhelp32Snapshot
CreateToolhelp32Snapshot= windll.kernel32.CreateToolhelp32Snapshot
CreateToolhelp32Snapshot.reltype = c_long
CreateToolhelp32Snapshot.argtypes = [ c_int , c_int ]
## Process32First
Process32First = windll.kernel32.Process32First
Process32First.argtypes = [ c_void_p , POINTER( PROCESSENTRY32 ) ]
Process32First.rettype = c_int
## Process32Next
Process32Next = windll.kernel32.Process32Next
Process32Next.argtypes = [ c_void_p , POINTER(PROCESSENTRY32) ]
Process32Next.rettype = c_int
## CloseHandle
CloseHandle = windll.kernel32.CloseHandle
CloseHandle.argtypes = [ c_void_p ]
CloseHandle.rettype = c_int
## Module32First
Module32First = windll.kernel32.Module32First
Module32First.argtypes = [ c_void_p , POINTER(MODULEENTRY32) ]
Module32First.rettype = c_int
hProcessSnap = c_void_p(0)
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS , 0 )
pe32 = PROCESSENTRY32()
pe32.dwSize = sizeof( PROCESSENTRY32 )
ret = Process32First( hProcessSnap , pointer( pe32 ) )
path = None
while ret :
if name + ".exe" == pe32.szExeFile:
hModuleSnap = c_void_p(0)
me32 = MODULEENTRY32()
me32.dwSize = sizeof( MODULEENTRY32 )
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pe32.th32ProcessID )
ret = Module32First( hModuleSnap, pointer(me32) )
path = me32.szExePath
CloseHandle( hModuleSnap )
if path:
break
ret = Process32Next( hProcessSnap, pointer(pe32) )
CloseHandle( hProcessSnap )
return path
def getRunningProcessExePathByName_posix(name):
pids= [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
path = os.readlink(os.path.join('/proc', pid, 'exe'))
if path and path.endswith(name):
return path
except:
pass
def getRunningProcessExePathByName(name):
try:
if hostos == "nt":
return getRunningProcessExePathByName_win32(name)
elif hostos == "posix":
return getRunningProcessExePathByName_posix(name)
else:
return None
except:
return None
class TestSuite(object):
def __init__(self, options, path = None):
self.options = options
self.path = path
self.error = None
self.setUp = None
self.tearDown = None
self.adb = None
self.targetos = None
self.nameprefix = "opencv_" + self.options.mode + "_"
for p in parse_patterns:
setattr(self, p["name"], p["default"])
if self.path:
cachefile = open(os.path.join(self.path, "CMakeCache.txt"), "rt")
try:
for l in cachefile.readlines():
ll = l.strip()
if not ll or ll.startswith("#"):
continue
for p in parse_patterns:
match = p["pattern"].match(ll)
if match:
value = match.groups()[0]
if value and not value.endswith("-NOTFOUND"):
setattr(self, p["name"], value)
except:
pass
cachefile.close()
# detect target platform
if self.android_executable or self.android_abi or self.ndk_path:
self.targetos = "android"
else:
self.targetos = hostos
self.initialize()
def initialize(self):
# fix empty tests dir
if not self.tests_dir:
self.tests_dir = self.path
self.tests_dir = os.path.normpath(self.tests_dir)
# compute path to adb
if self.android_executable:
self.adb = os.path.join(os.path.dirname(os.path.dirname(self.android_executable)), ("platform-tools/adb","platform-tools/adb.exe")[hostos == 'nt'])
if not os.path.isfile(self.adb) or not os.access(self.adb, os.X_OK):
self.adb = None
else:
self.adb = None
if self.targetos == "android":
# fix adb tool location
if not self.adb:
self.adb = getRunningProcessExePathByName("adb")
if not self.adb:
self.adb = "adb"
if self.options.adb_serial:
self.adb = [self.adb, "-s", self.options.adb_serial]
else:
self.adb = [self.adb]
try:
output = Popen(self.adb + ["shell", "ls"], stdout=PIPE, stderr=PIPE).communicate()
except OSError:
self.adb = []
# remember current device serial. Needed if another device is connected while this script runs
if self.adb and not self.options.adb_serial:
adb_res = self.runAdb("devices")
if not adb_res:
self.error = "Could not run adb command: %s (for %s)" % (self.error, self.path)
self.adb = []
else:
# assume here that device name may consists of any characters except newline
connected_devices = re.findall(r"^[^\n]+[ \t]+device\r?$", adb_res, re.MULTILINE)
if not connected_devices:
self.error = "Android device not found"
self.adb = []
elif len(connected_devices) != 1:
self.error = "Too many (%s) devices are connected. Please specify single device using --serial option:\n\n" % (len(connected_devices)) + adb_res
self.adb = []
else:
self.options.adb_serial = connected_devices[0].split("\t")[0]
self.adb = self.adb + ["-s", self.options.adb_serial]
if self.adb:
# construct name for aapt tool
self.aapt = [os.path.join(os.path.dirname(self.adb[0]), ("aapt","aapt.exe")[hostos == 'nt'])]
if not os.path.isfile(self.aapt[0]):
# it's moved in SDK r22
sdk_dir = os.path.dirname( os.path.dirname(self.adb[0]) )
aapt_fn = ("aapt", "aapt.exe")[hostos == 'nt']
for r, ds, fs in os.walk( os.path.join(sdk_dir, 'build-tools') ):
if aapt_fn in fs:
self.aapt = [ os.path.join(r, aapt_fn) ]
break
else:
self.error = "Can't find '%s' tool!" % aapt_fn
# fix has_perf_tests param
self.has_perf_tests = self.has_perf_tests == "ON"
self.has_accuracy_tests = self.has_accuracy_tests == "ON"
# fix is_x64 flag
self.is_x64 = self.is_x64 == "ON"
if not self.is_x64 and ("X64" in "%s %s %s" % (self.cxx_flags, self.cxx_flags_release, self.cxx_flags_debug) or "Win64" in self.cmake_generator):
self.is_x64 = True
# fix test path
if "Visual Studio" in self.cmake_generator:
if self.options.configuration:
self.tests_dir = os.path.join(self.tests_dir, self.options.configuration)
else:
self.tests_dir = os.path.join(self.tests_dir, self.build_type)
elif not self.is_x64 and self.cxx_compiler:
#one more attempt to detect x64 compiler
try:
compiler = [self.cxx_compiler]
if self.cxx_compiler_arg1:
compiler.append(self.cxx_compiler_arg1)
output = Popen(compiler + ["-v"], stdout=PIPE, stderr=PIPE).communicate()
if not output[0] and "x86_64" in output[1]:
self.is_x64 = True
except OSError:
pass
# detect target arch
if self.targetos == "android":
if "armeabi-v7a" in self.android_abi:
self.targetarch = "armv7a"
elif "armeabi-v6" in self.android_abi:
self.targetarch = "armv6"
elif "armeabi" in self.android_abi:
self.targetarch = "armv5te"
elif "x86" in self.android_abi:
self.targetarch = "x86"
elif "mips" in self.android_abi:
self.targetarch = "mips"
else:
self.targetarch = "ARM"
elif self.is_x64 and hostmachine in ["AMD64", "x86_64"]:
self.targetarch = "x64"
elif hostmachine in ["x86", "AMD64", "x86_64"]:
self.targetarch = "x86"
else:
self.targetarch = "unknown"
# fix CUDA attributes
self.with_cuda = self.with_cuda == "ON"
if self.cuda_library and self.cuda_library.endswith("-NOTFOUND"):
self.cuda_library = None
self.has_cuda = self.with_cuda and self.cuda_library and self.targetarch in ["x86", "x64"]
self.hardware = None
self.cmake_home_vcver = self.getVCVersion(self.cmake_home)
if self.opencv_home == self.cmake_home:
self.opencv_home_vcver = self.cmake_home_vcver
else:
self.opencv_home_vcver = self.getVCVersion(self.opencv_home)
self.tests = self.getAvailableTestApps()
def getVCVersion(self, root_path):
if not root_path:
return None
if os.path.isdir(os.path.join(root_path, ".svn")):
return self.getSvnVersion(root_path)
elif os.path.isdir(os.path.join(root_path, ".git")):
return self.getGitHash(root_path)
return None
def getGitHash(self, path):
if not path or not self.git_executable:
return None
try:
output = Popen([self.git_executable, "rev-parse", "--short", "HEAD"], stdout=PIPE, stderr=PIPE, cwd = path).communicate()
if not output[1]:
return output[0].strip()
else:
return None
except OSError:
return None
def getSvnVersion(self, path):
if not path:
val = None
elif not self.svnversion_path and hostos == 'nt':
val = self.tryGetSvnVersionWithTortoise(path)
else:
svnversion = self.svnversion_path
if not svnversion:
svnversion = "svnversion"
try:
output = Popen([svnversion, "-n", path], stdout=PIPE, stderr=PIPE).communicate()
if not output[1]:
val = output[0]
else:
val = None
except OSError:
val = None
if val:
val = val.replace(" ", "_")
return val
def tryGetSvnVersionWithTortoise(self, path):
try:
wcrev = "SubWCRev.exe"
dir = tempfile.mkdtemp()
#print dir
tmpfilename = os.path.join(dir, "svn.tmp")
tmpfilename2 = os.path.join(dir, "svn_out.tmp")
tmpfile = open(tmpfilename, "w")
tmpfile.write("$WCRANGE$$WCMODS?M:$")
tmpfile.close();
output = Popen([wcrev, path, tmpfilename, tmpfilename2, "-f"], stdout=PIPE, stderr=PIPE).communicate()
if "is not a working copy" in output[0]:
version = "exported"
else:
tmpfile = open(tmpfilename2, "r")
version = tmpfile.read()
tmpfile.close()
return version
except:
return None
finally:
if dir:
shutil.rmtree(dir)
def isTest(self, fullpath):
if not os.path.isfile(fullpath):
return False
if self.targetos == "nt" and not fullpath.endswith(".exe"):
return False
if hostos == self.targetos:
return os.access(fullpath, os.X_OK)
if self.targetos == "android" and fullpath.endswith(".apk"):
return True
return True
def getAvailableTestApps(self):
if self.tests_dir and os.path.isdir(self.tests_dir):
files = glob.glob(os.path.join(self.tests_dir, self.nameprefix + "*"))
files = [f for f in files if self.isTest(f)]
if self.ant_executable and self.java_test_binary_dir:
files.append("java")
return files
return []
def getLogName(self, app, timestamp):
app = os.path.basename(app)
if app.endswith(".exe"):
if app.endswith("d.exe"):
app = app[:-5]
else:
app = app[:-4]
if app.startswith(self.nameprefix):
app = app[len(self.nameprefix):]
if self.cmake_home_vcver:
if self.cmake_home_vcver == self.opencv_home_vcver:
rev = self.cmake_home_vcver
elif self.opencv_home_vcver:
rev = self.cmake_home_vcver + "-" + self.opencv_home_vcver
else:
rev = self.cmake_home_vcver
else:
rev = None
if rev:
rev = rev.replace(":","to")
else:
rev = ""
if self.options.useLongNames:
if not rev:
rev = "unknown"
tstamp = timestamp.strftime("%Y%m%d-%H%M%S")
features = []
#OS
_os = ""
if self.targetos == "android":
_os = "Android" + self.runAdb("shell", "getprop ro.build.version.release").strip()
else:
mv = platform.mac_ver()
if mv[0]:
_os = "Darwin" + mv[0]
else:
wv = platform.win32_ver()
if wv[0]:
_os = "Windows" + wv[0]
else:
lv = platform.linux_distribution()
if lv[0]:
_os = lv[0] + lv[1]
else:
_os = self.targetos
features.append(_os)
#HW(x86, x64, ARMv7a)
if self.targetarch:
features.append(self.targetarch)
#TBB
if ";tbb;" in self.core_dependencies:
features.append("TBB")
#CUDA
if self.has_cuda:
#TODO: determine compute capability
features.append("CUDA")
#SIMD
compiler_output = ""
try:
tmpfile = tempfile.mkstemp(suffix=".cpp", text = True)
fd = os.fdopen(tmpfile[0], "w+b")
fd.write(SIMD_DETECTION_PROGRAM)
fd.close();
options = [self.cxx_compiler]
if self.cxx_compiler_arg1:
options.append(self.cxx_compiler_arg1)
cxx_flags = self.cxx_flags + " " + self.cxx_flags_release + " " + self.opencv_cxx_flags + " " + self.opencv_cxx_flags_release
if self.targetos == "android" and self.cxx_flags_android:
cxx_flags = self.cxx_flags_android + " " + cxx_flags
prev_option = None
for opt in cxx_flags.split(" "):
if opt.count('\"') % 2 == 1:
if prev_option is None:
prev_option = opt
else:
options.append(prev_option + " " + opt)
prev_option = None
elif prev_option is None:
options.append(opt)
else:
prev_option = prev_option + " " + opt
options.append(tmpfile[1])
output = Popen(options, stdout=PIPE, stderr=PIPE).communicate()
compiler_output = output[1]
os.remove(tmpfile[1])
except OSError:
pass
if compiler_output:
m = re.search("#error\W+(\w+)", compiler_output)
if m:
features.append(m.group(1))
#fin
return "%s__%s__%s__%s.xml" % (app, rev, tstamp, "_".join(features))
else:
if rev:
rev = rev + "_"
if self.hardware:
hw = str(self.hardware).replace(" ", "_") + "_"
elif self.has_cuda:
hw = "CUDA_"
else:
hw = ""
tstamp = timestamp.strftime("%Y%m%d-%H%M%S")
lname = "%s_%s_%s_%s%s%s.xml" % (app, self.targetos, self.targetarch, hw, rev, tstamp)
lname = str.replace(lname, '(', '_')
lname = str.replace(lname, ')', '_')
return lname
def getTest(self, name):
# full path
if self.isTest(name):
return name
# name only
fullname = os.path.join(self.tests_dir, name)
if self.isTest(fullname):
return fullname
# name without extension
fullname += ".exe"
if self.isTest(fullname):
return fullname
if self.targetos == "android":
fullname += ".apk"
if self.isTest(fullname):
return fullname
# short name for OpenCV tests
for t in self.tests:
if t == name:
return t
fname = os.path.basename(t)
if fname == name:
return t
if fname.endswith(".exe") or (self.targetos == "android" and fname.endswith(".apk")):
fname = fname[:-4]
if fname == name:
return t
if self.options.configuration == "Debug" and fname == name + 'd':
return t
if fname.startswith(self.nameprefix):
fname = fname[len(self.nameprefix):]
if fname == name:
return t
if self.options.configuration == "Debug" and fname == name + 'd':
return t
return None
def runAdb(self, *args):
cmd = self.adb[:]
cmd.extend(args)
try:
output = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
if not output[1]:
return output[0]
self.error = output[1]
except OSError:
pass
return None
def isRunnable(self):
if self.error:
return False
if self.targetarch == "x64" and hostmachine == "x86":
self.error = "Target architecture is incompatible with current platform (at %s)" % self.path
return False
if self.targetos == "android":
if not self.adb:
self.error = "Could not find adb executable (for %s)" % self.path
return False
if "armeabi-v7a" in self.android_abi:
adb_res = self.runAdb("shell", "cat /proc/cpuinfo")
if not adb_res:
self.error = "Could not get info about Android platform: %s (for %s)" % (self.error, self.path)
return False
if "ARMv7" not in adb_res:
self.error = "Android device does not support ARMv7 commands, but tests are built for armeabi-v7a (for %s)" % self.path
return False
if "NEON" in self.android_abi and "neon" not in adb_res:
self.error = "Android device has no NEON, but tests are built for %s (for %s)" % (self.android_abi, self.path)
return False
hw = re.search(r"^Hardware[ \t]*:[ \t]*(.*?)$", adb_res, re.MULTILINE)
if hw:
self.hardware = hw.groups()[0].strip()
return True
def runTest(self, path, workingDir, _stdout, _stderr, args = []):
global errorCode
if self.error:
return
args = args[:]
timestamp = datetime.datetime.now()
logfile = self.getLogName(path, timestamp)
exe = os.path.abspath(path)
userlog = [a for a in args if a.startswith("--gtest_output=")]
if len(userlog) == 0:
args.append("--gtest_output=xml:" + logfile)
else:
logfile = userlog[0][userlog[0].find(":")+1:]
if self.targetos == "android" and exe.endswith(".apk"):
print "Run java tests:", exe
try:
# get package info
output = Popen(self.aapt + ["dump", "xmltree", exe, "AndroidManifest.xml"], stdout=PIPE, stderr=_stderr).communicate()
if not output[0]:
print >> _stderr, "fail to dump manifest from", exe
return
tags = re.split(r"[ ]+E: ", output[0])
# get package name
manifest_tag = [t for t in tags if t.startswith("manifest ")]
if not manifest_tag:
print >> _stderr, "fail to read package name from", exe
return
pkg_name = re.search(r"^[ ]+A: package=\"(?P<pkg>.*?)\" \(Raw: \"(?P=pkg)\"\)\r?$", manifest_tag[0], flags=re.MULTILINE).group("pkg")
# get test instrumentation info
instrumentation_tag = [t for t in tags if t.startswith("instrumentation ")]
if not instrumentation_tag:
print >> _stderr, "can not find instrumentation detials in", exe
return
pkg_runner = re.search(r"^[ ]+A: android:name\(0x[0-9a-f]{8}\)=\"(?P<runner>.*?)\" \(Raw: \"(?P=runner)\"\)\r?$", instrumentation_tag[0], flags=re.MULTILINE).group("runner")
pkg_target = re.search(r"^[ ]+A: android:targetPackage\(0x[0-9a-f]{8}\)=\"(?P<pkg>.*?)\" \(Raw: \"(?P=pkg)\"\)\r?$", instrumentation_tag[0], flags=re.MULTILINE).group("pkg")
if not pkg_name or not pkg_runner or not pkg_target:
print >> _stderr, "can not find instrumentation detials in", exe
return
if self.options.junit_package:
if self.options.junit_package.startswith("."):
pkg_target += self.options.junit_package
else:
pkg_target = self.options.junit_package
# uninstall previously installed package
print >> _stderr, "Uninstalling old", pkg_name, "from device..."
Popen(self.adb + ["uninstall", pkg_name], stdout=PIPE, stderr=_stderr).communicate()
print >> _stderr, "Installing new", exe, "to device...",
output = Popen(self.adb + ["install", exe], stdout=PIPE, stderr=PIPE).communicate()
if output[0] and output[0].strip().endswith("Success"):
print >> _stderr, "Success"
else:
print >> _stderr, "Failure"
print >> _stderr, "Failed to install", exe, "to device"
return
print >> _stderr, "Running jUnit tests for ", pkg_target
if self.setUp:
self.setUp()
Popen(self.adb + ["shell", "am instrument -w -e package " + pkg_target + " " + pkg_name + "/" + pkg_runner], stdout=_stdout, stderr=_stderr).wait()
if self.tearDown:
self.tearDown()
except OSError:
pass
return
elif self.targetos == "android":
hostlogpath = ""
usercolor = [a for a in args if a.startswith("--gtest_color=")]
if len(usercolor) == 0 and _stdout.isatty() and hostos != "nt":
args.append("--gtest_color=yes")
try:
tempdir = "/data/local/tmp/"
andoidcwd = tempdir + getpass.getuser().replace(" ","") + "_" + self.options.mode +"/"
exename = os.path.basename(exe)
androidexe = andoidcwd + exename
# upload
_stderr.write("Uploading... ")
output = Popen(self.adb + ["push", exe, androidexe], stdout=_stdout, stderr=_stderr).wait()
if output != 0:
print >> _stderr, "adb finishes unexpectedly with error code", output
return
# chmod
output = Popen(self.adb + ["shell", "chmod 777 " + androidexe], stdout=_stdout, stderr=_stderr).wait()
if output != 0:
print >> _stderr, "adb finishes unexpectedly with error code", output
return
# run
if self.options.help:
command = exename + " --help"
else:
command = exename + " " + " ".join(args)
print >> _stderr, "Run command:", command
if self.setUp:
self.setUp()
env = self.options.android_env.copy()
env['OPENCV_TEST_DATA_PATH'] = self.options.test_data_path
if self.options.android_propagate_opencv_env:
for k, v in os.environ.items():
if k.startswith('OPENCV') and not k in env:
env[k] = v
print >> _stderr, "Android environment variables: \n", '\n'.join([' %s=%s' % (k, v) for k, v in env.items()])
commandPrefix = ''.join(['export %s=%s && ' % (k, v) for k, v in env.items()])
Popen(self.adb + ["shell", commandPrefix + "cd " + andoidcwd + "&& ./" + command], stdout=_stdout, stderr=_stderr).wait()
if self.tearDown:
self.tearDown()
# try get log
if not self.options.help:
#_stderr.write("Pull log... ")
hostlogpath = os.path.join(workingDir, logfile)
output = Popen(self.adb + ["pull", andoidcwd + logfile, hostlogpath], stdout=_stdout, stderr=PIPE).wait()
if output != 0:
print >> _stderr, "adb finishes unexpectedly with error code", output
return
#rm log
Popen(self.adb + ["shell", "rm " + andoidcwd + logfile], stdout=PIPE, stderr=PIPE).wait()
# clean temporary files
Popen(self.adb + ["shell", "rm " + tempdir + "__opencv_temp.*"], stdout=PIPE, stderr=PIPE).wait()
except OSError:
pass
if os.path.isfile(hostlogpath):
return hostlogpath
return None
elif path == "java":
cmd = [self.ant_executable,
"-Dopencv.build.type="
+ (self.options.configuration if self.options.configuration else self.build_type),
"buildAndTest"]
print >> _stderr, "Run command:", " ".join(cmd)
try:
errorCode = Popen(cmd, stdout=_stdout, stderr=_stderr, cwd = self.java_test_binary_dir + "/.build").wait()
except:
print "Unexpected error:", sys.exc_info()[0]
return None
else:
cmd = [exe]
if self.options.help:
cmd.append("--help")
else:
cmd.extend(args)
orig_temp_path = os.environ.get('OPENCV_TEMP_PATH')
temp_path = tempfile.mkdtemp(prefix="__opencv_temp.", dir=orig_temp_path or None)
os.environ['OPENCV_TEMP_PATH'] = temp_path
print >> _stderr, "Run command:", " ".join(cmd)
try:
errorCode = Popen(cmd, stdout=_stdout, stderr=_stderr, cwd = workingDir).wait()
except:
print "Unexpected error:", sys.exc_info()[0]
# clean temporary files
if orig_temp_path:
os.environ['OPENCV_TEMP_PATH'] = orig_temp_path
else:
del os.environ['OPENCV_TEMP_PATH']
try:
shutil.rmtree(temp_path)
pass
except:
pass
logpath = os.path.join(workingDir, logfile)
if os.path.isfile(logpath):
return logpath
return None
def runTests(self, tests, _stdout, _stderr, workingDir, args = []):
if not self.isRunnable():
print >> _stderr, "Error:", self.error
if self.error:
return []
if self.adb and self.targetos == "android":
print "adb command:", " ".join(self.adb)
if not tests:
tests = self.tests
logs = []
for test in tests:
t = self.getTest(test)
if t:
logfile = self.runTest(t, workingDir, _stdout, _stderr, args)
if logfile:
logs.append(os.path.relpath(logfile, "."))
else:
print >> _stderr, "Error: Test \"%s\" is not found in %s" % (test, self.tests_dir)
return logs
def getRunArgs(args):
run_args = []
for path in args:
path = os.path.abspath(path)
while (True):
if os.path.isdir(path) and os.path.isfile(os.path.join(path, "CMakeCache.txt")):
run_args.append(path)
break
npath = os.path.dirname(path)
if npath == path:
break
path = npath
return run_args
import os, sys
import argparse
import logging
from run_utils import Err, CMakeCache, log, execute
from run_suite import TestSuite
from run_android import AndroidTestSuite
epilog = '''
NOTE:
Additional options starting with "--gtest_" and "--perf_" will be passed directly to the test executables.
'''
if __name__ == "__main__":
test_args = [a for a in sys.argv if a.startswith("--perf_") or a.startswith("--gtest_")]
argv = [a for a in sys.argv if not(a.startswith("--perf_") or a.startswith("--gtest_"))]
parser = OptionParser()
parser.add_option("-t", "--tests", dest="tests", help="comma-separated list of modules to test", metavar="SUITS", default="")
parser.add_option("-w", "--cwd", dest="cwd", help="working directory for tests", metavar="PATH", default=".")
parser.add_option("-a", "--accuracy", dest="accuracy", help="look for accuracy tests instead of performance tests", action="store_true", default=False)
parser.add_option("-l", "--longname", dest="useLongNames", action="store_true", help="generate log files with long names", default=False)
parser.add_option("", "--android_test_data_path", dest="test_data_path", help="OPENCV_TEST_DATA_PATH for Android run", metavar="PATH", default="/sdcard/opencv_testdata/")
parser.add_option("", "--android_env", dest="android_env_array", help="Environment variable for Android run (NAME=VALUE)", action='append')
parser.add_option("", "--android_propagate_opencv_env", dest="android_propagate_opencv_env", help="Propagate OPENCV* environment variables for Android run", action="store_true", default=False)
parser.add_option("", "--configuration", dest="configuration", help="force Debug or Release configuration", metavar="CFG", default="")
parser.add_option("", "--serial", dest="adb_serial", help="Android: directs command to the USB device or emulator with the given serial number", metavar="serial number", default="")
parser.add_option("", "--package", dest="junit_package", help="Android: run jUnit tests for specified package", metavar="package", default="")
parser.add_option("", "--help-tests", dest="help", help="Show help for test executable", action="store_true", default=False)
parser.add_option("", "--check", dest="check", help="Shortcut for '--perf_min_samples=1 --perf_force_samples=1'", action="store_true", default=False)
parser.add_option("", "--list", dest="list", help="List available tests", action="store_true", default=False)
(options, args) = parser.parse_args(argv)
if options.accuracy:
options.mode = "test"
else:
options.mode = "perf"
run_args = getRunArgs(args[1:] or ['.'])
if len(run_args) == 0:
print >> sys.stderr, "Usage:", os.path.basename(sys.argv[0]), "[options] [build_path]"
# log.basicConfig(format='[%(levelname)s] %(message)s', level = log.DEBUG)
# log.basicConfig(format='[%(levelname)s] %(message)s', level = log.INFO)
parser = argparse.ArgumentParser(
description='OpenCV test runner script',
epilog=epilog,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("build_path", nargs = "*", default = ["."], help="Path to build directory (should contain CMakeCache.txt, default is current) or to directory with tests (all platform checks will be disabled in this case)")
parser.add_argument("-t", "--tests", metavar="MODULES", default="", help="Comma-separated list of modules to test (example: -t core,imgproc,java)")
parser.add_argument("-b", "--blacklist", metavar="MODULES", default="", help="Comma-separated list of modules to exclude from test (example: -b java)")
parser.add_argument("-a", "--accuracy", action="store_true", default=False, help="Look for accuracy tests instead of performance tests")
parser.add_argument("--check", action="store_true", default=False, help="Shortcut for '--perf_min_samples=1 --perf_force_samples=1'")
parser.add_argument("-w", "--cwd", metavar="PATH", default=".", help="Working directory for tests (default is current)")
parser.add_argument("-l", "--longname", action="store_true", default=False, help="Generate log files with long names")
parser.add_argument("--list", action="store_true", default=False, help="List available tests (executables)")
parser.add_argument("--list_short", action="store_true", default=False, help="List available tests (aliases)")
parser.add_argument("--list_short_main", action="store_true", default=False, help="List available tests (main repository, aliases)")
parser.add_argument("--configuration", metavar="CFG", default="", help="Visual Studio: force Debug or Release configuration")
parser.add_argument("-n", "--dry_run", action="store_true", help="Do not run the tests")
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Print more debug information")
# Valgrind
parser.add_argument("--valgrind", action="store_true", default=False, help="Run C++ tests in valgrind")
parser.add_argument("--valgrind_supp", metavar="FILE", help="Path to valgrind suppression file (example: --valgrind_supp opencv/platforms/scripts/valgrind.supp)")
parser.add_argument("--valgrind_opt", metavar="OPT", action="append", default=[], help="Add command line option to valgrind (example: --valgrind_opt=--leak-check=full)")
# Android
parser.add_argument("--android", action="store_true", default=False, help="Android: force all tests to run on device")
parser.add_argument("--android_sdk", metavar="PATH", help="Android: path to SDK to use adb and aapt tools")
parser.add_argument("--android_test_data_path", metavar="PATH", default="/sdcard/opencv_testdata/", help="Android: path to testdata on device")
parser.add_argument("--android_env", action='append', help="Android: add environment variable (NAME=VALUE)")
parser.add_argument("--android_propagate_opencv_env", action="store_true", default=False, help="Android: propagate OPENCV* environment variables")
parser.add_argument("--serial", metavar="serial number", default="", help="Android: directs command to the USB device or emulator with the given serial number")
parser.add_argument("--package", metavar="package", default="", help="Android: run jUnit tests for specified package")
args, other_args = parser.parse_known_args()
log.setLevel(logging.DEBUG if args.verbose else logging.INFO)
test_args = [a for a in other_args if a.startswith("--perf_") or a.startswith("--gtest_")]
bad_args = [a for a in other_args if a not in test_args]
if len(bad_args) > 0:
log.error("Error: Bad arguments: %s", bad_args)
exit(1)
options.android_env = {}
if options.android_env_array:
for entry in options.android_env_array:
k, v = entry.split("=", 1)
options.android_env[k] = v
args.mode = "test" if args.accuracy else "perf"
android_env = []
if args.android_env:
android_env.extend([entry.split("=", 1) for entry in args.android_env])
if args.android_propagate_opencv_env:
android_env.extend([entry for entry in os.environ.items() if entry[0].startswith('OPENCV')])
android_env = dict(android_env)
if args.android_test_data_path:
android_env['OPENCV_TEST_DATA_PATH'] = args.android_test_data_path
tests = [s.strip() for s in options.tests.split(",") if s]
if args.valgrind:
try:
ver = execute(["valgrind", "--version"], silent=True)
log.debug("Using %s", ver)
except OSError as e:
log.error("Failed to run valgrind: %s", e)
exit(1)
if len(tests) != 1 or len(run_args) != 1:
# remove --gtest_output from params
if len(args.build_path) != 1:
test_args = [a for a in test_args if not a.startswith("--gtest_output=")]
if options.check:
if args.check:
if not [a for a in test_args if a.startswith("--perf_min_samples=")] :
test_args.extend(["--perf_min_samples=1"])
if not [a for a in test_args if a.startswith("--perf_force_samples=")] :
......@@ -902,22 +89,46 @@ if __name__ == "__main__":
if not [a for a in test_args if a.startswith("--perf_verify_sanity")] :
test_args.extend(["--perf_verify_sanity"])
ret = 0
logs = []
test_list = []
for path in run_args:
suite = TestSuite(options, path)
#print vars(suite),"\n"
if options.list:
test_list.extend(suite.tests)
else:
logs.extend(suite.runTests(tests, sys.stdout, sys.stderr, options.cwd, test_args))
for path in args.build_path:
try:
if not os.path.isdir(path):
raise Err("Not a directory (should contain CMakeCache.txt ot test executables)")
cache = CMakeCache()
fname = os.path.join(path, "CMakeCache.txt")
if os.path.isfile(fname):
log.debug("Reading cmake cache file: %s", fname)
cache.read(path, fname, args.configuration)
else:
log.debug("Assuming folder contains tests: %s", path)
cache.setDummy(path)
if options.list:
print os.linesep.join(test_list) or "No tests found"
if args.android or cache.getOS() == "android":
log.debug("Creating Android test runner")
suite = AndroidTestSuite(args, cache, android_env)
else:
log.debug("Creating native test runner")
suite = TestSuite(args, cache)
if args.list or args.list_short or args.list_short_main:
suite.listTests(args.list_short or args.list_short_main, args.list_short_main)
else:
log.debug("Running tests in '%s', working dir: '%s'", path, args.cwd)
def parseTests(s):
return [o.strip() for o in s.split(",") if o]
l, r = suite.runTests(parseTests(args.tests), parseTests(args.blacklist), args.cwd, test_args)
logs.extend(l)
if r != 0:
ret = r
except Err as e:
log.error("ERROR: test path '%s' ==> %s", path, e.msg)
ret = -1
if logs:
print >> sys.stderr, "Collected: ", " ".join(logs)
log.warning("Collected: %s", ", ".join(logs))
if errorCode != 0:
print "Error code: ", errorCode, (" (0x%x)" % (errorCode & 0xffffffff))
exit(errorCode)
if ret != 0:
log.error("ERROR: some tests have failed")
exit(ret)
#!/usr/bin/env python
import sys
from run_utils import *
from run_suite import TestSuite
def exe(program):
return program + ".exe" if hostos == 'nt' else program
class ApkInfo:
def __init__(self):
self.pkg_name = None
self.pkg_target = None
self.pkg_runner = None
def forcePackage(self, package):
if package:
if package.startswith("."):
self.pkg_target += package
else:
self.pkg_target = package
#==============================================================================
class Tool:
def __init__(self):
self.cmd = []
def run(self, args = [], silent = False):
cmd = self.cmd[:]
cmd.extend(args)
return execute(self.cmd + args, silent)
#==============================================================================
class Adb(Tool):
def __init__(self, sdk_dir):
Tool.__init__(self)
exe_path = os.path.join(sdk_dir, exe("platform-tools/adb"))
if not os.path.isfile(exe_path) or not os.access(exe_path, os.X_OK):
exe_path = None
# fix adb tool location
if not exe_path:
exe_path = getRunningProcessExePathByName("adb")
if not exe_path:
exe_path = "adb"
self.cmd = [exe_path]
self.cpuinfo = ""
def init(self, serial):
# remember current device serial. Needed if another device is connected while this script runs
if not serial:
serial = self.detectSerial()
if serial:
self.cmd.extend(["-s", serial])
# read device cpuinfo
self.cpuinfo = self.run(["shell", "cat /proc/cpuinfo"], silent = True)
if not self.cpuinfo:
raise Err("Can not get cpuinfo from Android device")
def detectSerial(self):
adb_res = self.run(["devices"], silent = True)
# assume here that device name may consists of any characters except newline
connected_devices = re.findall(r"^[^\n]+[ \t]+device\r?$", adb_res, re.MULTILINE)
if not connected_devices:
raise Err("Can not find Android device")
elif len(connected_devices) != 1:
raise Err("Too many (%s) devices are connected. Please specify single device using --serial option:\n\n%s", len(connected_devices), adb_res)
else:
return connected_devices[0].split("\t")[0]
def getOSIdentifier(self):
return "Android" + self.run(["shell", "getprop ro.build.version.release"], silent = True).strip()
def getHardware(self):
hw = re.search(r"^Hardware[ \t]*:[ \t]*(.*?)$", self.cpuinfo, re.MULTILINE)
if hw:
return hw.group(1).strip()
def checkArmHardware(self, expected_abi):
if expected_abi and "armeabi-v7a" in expected_abi:
if "ARMv7" not in self.cpuinfo:
raise Err("Android device does not support ARMv7 commands, but tests are built for armeabi-v7a")
if "NEON" in expected_abi and "neon" not in self.cpuinfo:
raise Err("Android device has no NEON, but tests are built for %s", expected_abi)
#==============================================================================
class Aapt(Tool):
def __init__(self, sdk_dir):
Tool.__init__(self)
aapt_fn = exe("aapt")
aapt = None
for r, ds, fs in os.walk( os.path.join(sdk_dir, 'build-tools') ):
if aapt_fn in fs:
aapt = os.path.join(r, aapt_fn)
break
if not aapt:
raise Err("Can not find aapt tool: %s", aapt_fn)
self.cmd = [aapt]
def dump(self, exe):
res = ApkInfo()
output = self.run(["dump", "xmltree", exe, "AndroidManifest.xml"], silent = True)
if not output:
raise Err("Can not dump manifest from %s", exe)
tags = re.split(r"[ ]+E: ", output)
# get package name
manifest_tag = [t for t in tags if t.startswith("manifest ")]
if not manifest_tag:
raise Err("Can not read package name from: %s", exe)
res.pkg_name = re.search(r"^[ ]+A: package=\"(?P<pkg>.*?)\" \(Raw: \"(?P=pkg)\"\)\r?$", manifest_tag[0], flags=re.MULTILINE).group("pkg")
# get test instrumentation info
instrumentation_tag = [t for t in tags if t.startswith("instrumentation ")]
if not instrumentation_tag:
raise Err("Can not find instrumentation detials in: %s", exe)
res.pkg_runner = re.search(r"^[ ]+A: android:name\(0x[0-9a-f]{8}\)=\"(?P<runner>.*?)\" \(Raw: \"(?P=runner)\"\)\r?$", instrumentation_tag[0], flags=re.MULTILINE).group("runner")
res.pkg_target = re.search(r"^[ ]+A: android:targetPackage\(0x[0-9a-f]{8}\)=\"(?P<pkg>.*?)\" \(Raw: \"(?P=pkg)\"\)\r?$", instrumentation_tag[0], flags=re.MULTILINE).group("pkg")
if not res.pkg_name or not res.pkg_runner or not res.pkg_target:
raise Err("Can not find instrumentation detials in: %s", exe)
return res
#===================================================================================================
class AndroidTestSuite(TestSuite):
def __init__(self, options, cache, android_env = {}):
TestSuite.__init__(self, options, cache)
sdk_dir = options.android_sdk or os.environ.get("ANDROID_SDK", False) or os.path.dirname(os.path.dirname(self.cache.android_executable))
log.debug("Detecting Android tools in directory: %s", sdk_dir)
self.adb = Adb(sdk_dir)
self.aapt = Aapt(sdk_dir)
self.env = android_env
def isTest(self, fullpath):
if os.path.isfile(fullpath):
if fullpath.endswith(".apk") or os.access(fullpath, os.X_OK):
return True
return False
def getOS(self):
return self.adb.getOSIdentifier()
def getHardware(self):
return [self.adb.getHardware()]
def checkPrerequisites(self):
self.adb.init(self.options.serial)
self.adb.checkArmHardware(self.cache.android_abi)
def runTest(self, path, logfile, workingDir, args = []):
args = args[:]
exe = os.path.abspath(path)
if exe.endswith(".apk"):
info = self.aapt.dump(exe)
if not info:
raise Err("Can not read info from test package: %s", exe)
info.forcePackage(self.options.package)
self.adb.run(["uninstall", info.pkg_name])
output = self.adb.run(["install", exe], silent = True)
if not (output and "Success" in output):
raise Err("Can not install package: %s", exe)
params = ["-e package %s" % info.pkg_target]
ret = self.adb.run(["shell", "am instrument -w %s %s/%s" % (" ".join(params), info.pkg_name, info.pkg_runner)])
return None, ret
else:
device_dir = getpass.getuser().replace(" ","") + "_" + self.options.mode +"/"
if isColorEnabled(args):
args.append("--gtest_color=yes")
tempdir = "/data/local/tmp/"
android_dir = tempdir + device_dir
exename = os.path.basename(exe)
android_exe = android_dir + exename
self.adb.run(["push", exe, android_exe])
self.adb.run(["shell", "chmod 777 " + android_exe])
env_pieces = ["export %s=%s" % (a,b) for a,b in self.env.items()]
pieces = ["cd %s" % android_dir, "./%s %s" % (exename, " ".join(args))]
log.warning("Run: %s" % " && ".join(pieces))
ret = self.adb.run(["shell", " && ".join(env_pieces + pieces)])
# try get log
hostlogpath = os.path.join(workingDir, logfile)
self.adb.run(["pull", android_dir + logfile, hostlogpath])
# cleanup
self.adb.run(["shell", "rm " + android_dir + logfile])
self.adb.run(["shell", "rm " + tempdir + "__opencv_temp.*"], silent = True)
if os.path.isfile(hostlogpath):
return hostlogpath, ret
return None, ret
#===================================================================================================
if __name__ == "__main__":
log.error("This is utility file, please execute run.py script")
#!/usr/bin/env python
import datetime
from run_utils import *
class TestSuite(object):
def __init__(self, options, cache):
self.options = options
self.cache = cache
self.nameprefix = "opencv_" + self.options.mode + "_"
self.tests = self.cache.gatherTests(self.nameprefix + "*", self.isTest)
def getOS(self):
return getPlatformVersion() or self.cache.getOS()
def getHardware(self):
res = []
if self.cache.getArch() in ["x86", "x64"] and self.cache.withCuda():
res.append("CUDA")
return res
def getLogName(self, app, timestamp):
app = self.getAlias(app)
rev = self.cache.getGitVersion()
if isinstance(timestamp, datetime.datetime):
timestamp = timestamp.strftime("%Y%m%d-%H%M%S")
if self.options.longname:
small_pieces = [self.getOS(), self.cache.getArch()] + self.cache.getDependencies() + self.getHardware() + [self.cache.getSIMDFeatures()]
big_pieces = [app, str(rev), timestamp, "_".join([p for p in small_pieces if p])]
l = "__".join(big_pieces)
else:
pieces = [app, self.cache.getOS(), self.cache.getArch()] + self.getHardware() + [rev, timestamp]
lname = "_".join([p for p in pieces if p])
lname = re.sub(r'[\(\)\[\]\s,]', '_', lname)
l = re.sub(r'_+', '_', lname)
return l + ".xml"
def listTests(self, short = False, main = False):
if len(self.tests) == 0:
raise Err("No tests found")
for t in self.tests:
if short:
t = self.getAlias(t)
if not main or self.cache.isMainModule(t):
log.info("%s", t)
def getAlias(self, fname):
return sorted(self.getAliases(fname), key = len)[0]
def getAliases(self, fname):
# input is full path ('/home/.../bin/opencv_test_core') or 'java'
res = [fname]
fname = os.path.basename(fname)
res.append(fname) # filename (opencv_test_core.exe)
noext = re.sub(r"\.(exe|apk)$", '', fname)
res.append(noext) # filename w/o extension (opencv_test_core)
nopref = None
if fname.startswith(self.nameprefix):
nopref = fname[len(self.nameprefix):]
res.append(nopref) # filename w/o prefix (core)
if noext.startswith(self.nameprefix):
res.append(noext[len(self.nameprefix):])
if self.options.configuration == "Debug":
res.append(re.sub(r"d$", '', noext)) # MSVC debug config, remove 'd' suffix
if nopref:
res.append(re.sub(r"d$", '', nopref)) # MSVC debug config, remove 'd' suffix
return set(res)
def getTest(self, name):
# return stored test name by provided alias
for t in self.tests:
if name in self.getAliases(t):
return t
raise Err("Can not find test: %s", name)
def getTestList(self, white, black):
res = [t for t in white or self.tests if self.getAlias(t) not in black]
if len(res) == 0:
raise Err("No tests found")
return set(res)
def isTest(self, fullpath):
if fullpath == "java":
return True
if not os.path.isfile(fullpath):
return False
if self.cache.getOS() == "nt" and not fullpath.endswith(".exe"):
return False
return os.access(fullpath, os.X_OK)
def wrapInValgrind(self, cmd = []):
if self.options.valgrind:
res = ['valgrind']
if self.options.valgrind_supp:
res.append("--suppressions=%s" % self.options.valgrind_supp)
res.extend(self.options.valgrind_opt)
return res + cmd
return cmd
def runTest(self, path, logfile, workingDir, args = []):
args = args[:]
exe = os.path.abspath(path)
if path == "java":
cfg = self.cache.build_type
if self.options.configuration:
cfg = self.options.configuration
cmd = [self.cache.ant_executable, "-Dopencv.build.type=%s" % cfg, "buildAndTest"]
ret = execute(cmd, cwd = self.cache.java_test_binary_dir + "/.build")
return None, ret
else:
if isColorEnabled(args):
args.append("--gtest_color=yes")
cmd = self.wrapInValgrind([exe] + args)
tempDir = TempEnvDir('OPENCV_TEMP_PATH', "__opencv_temp.")
tempDir.init()
log.warning("Run: %s" % " ".join(cmd))
ret = execute(cmd, cwd = workingDir)
tempDir.clean()
hostlogpath = os.path.join(workingDir, logfile)
if os.path.isfile(hostlogpath):
return hostlogpath, ret
return None, ret
def checkPrerequisites(self):
if self.cache.getArch() == "x64" and hostmachine == "x86":
raise Err("Target architecture is incompatible with current platform")
def runTests(self, tests, black, workingDir, args = []):
self.checkPrerequisites()
args = args[:]
logs = []
test_list = self.getTestList(tests, black)
date = datetime.datetime.now()
if len(test_list) != 1:
args = [a for a in args if not a.startswith("--gtest_output=")]
ret = 0
for test in test_list:
more_args = []
exe = self.getTest(test)
userlog = [a for a in args if a.startswith("--gtest_output=")]
if len(userlog) == 0:
logname = self.getLogName(exe, date)
more_args.append("--gtest_output=xml:" + logname)
else:
logname = userlog[0][userlog[0].find(":")+1:]
log.debug("Running the test: %s (%s) ==> %s in %s", exe, args + more_args, logname, workingDir)
if self.options.dry_run:
logfile, r = None, 0
else:
logfile, r = self.runTest(exe, logname, workingDir, args + more_args)
log.debug("Test returned: %s ==> %s", r, logfile)
if r != 0:
ret = r
if logfile:
logs.append(os.path.relpath(logfile, workingDir))
return logs, ret
#===================================================================================================
if __name__ == "__main__":
log.error("This is utility file, please execute run.py script")
#!/usr/bin/env python
import sys, os, platform, re, tempfile, glob, getpass, logging
from subprocess import check_call, check_output, CalledProcessError, STDOUT
hostos = os.name # 'nt', 'posix'
hostmachine = platform.machine() # 'x86', 'AMD64', 'x86_64'
def initLogger():
l = logging.getLogger("run.py")
l.setLevel(logging.DEBUG)
ch = logging.StreamHandler(sys.stderr)
ch.setFormatter(logging.Formatter("%(message)s"))
l.addHandler(ch)
return l
log = initLogger()
#===================================================================================================
class Err(Exception):
def __init__(self, msg, *args):
self.msg = msg % args
def execute(cmd, silent = False, cwd = "."):
try:
log.debug("Run: %s", cmd)
if silent:
return check_output(cmd, stderr = STDOUT, cwd = cwd).decode("latin-1")
else:
return check_call(cmd, cwd = cwd)
except CalledProcessError as e:
if silent:
log.debug("Process returned: %d", e.returncode)
return e.output.decode("latin-1")
else:
log.error("Process returned: %d", e.returncode)
return e.returncode
def isColorEnabled(args):
usercolor = [a for a in args if a.startswith("--gtest_color=")]
return len(usercolor) == 0 and sys.stdout.isatty() and hostos != "nt"
#===================================================================================================
def getPlatformVersion():
mv = platform.mac_ver()
if mv[0]:
return "Darwin" + mv[0]
else:
wv = platform.win32_ver()
if wv[0]:
return "Windows" + wv[0]
else:
lv = platform.linux_distribution()
if lv[0]:
return lv[0] + lv[1]
return None
def readGitVersion(git, path):
if not path or not git or not os.path.isdir(os.path.join(path, ".git")):
return None
try:
output = execute([git, "-C", path, "rev-parse", "--short", "HEAD"], silent = True)
return output.strip()
except OSError:
log.warning("Git version read failed")
return None
SIMD_DETECTION_PROGRAM="""
#if __SSE5__
# error SSE5
#endif
#if __AVX2__
# error AVX2
#endif
#if __AVX__
# error AVX
#endif
#if __SSE4_2__
# error SSE4.2
#endif
#if __SSE4_1__
# error SSE4.1
#endif
#if __SSSE3__
# error SSSE3
#endif
#if __SSE3__
# error SSE3
#endif
#if __AES__
# error AES
#endif
#if __SSE2__
# error SSE2
#endif
#if __SSE__
# error SSE
#endif
#if __3dNOW__
# error 3dNOW
#endif
#if __MMX__
# error MMX
#endif
#if __ARM_NEON__
# error NEON
#endif
#error NOSIMD
"""
def testSIMD(compiler, cxx_flags, compiler_arg = None):
if not compiler:
return None
compiler_output = ""
try:
_, tmpfile = tempfile.mkstemp(suffix=".cpp", text = True)
with open(tmpfile, "w+") as fd:
fd.write(SIMD_DETECTION_PROGRAM)
options = [compiler]
if compiler_arg:
options.append(compiler_arg)
prev_option = None
for opt in " ".join(cxx_flags).split():
if opt.count('\"') % 2 == 1:
if prev_option is None:
prev_option = opt
else:
options.append(prev_option + " " + opt)
prev_option = None
elif prev_option is None:
options.append(opt)
else:
prev_option = prev_option + " " + opt
options.append(tmpfile)
compiler_output = execute(options, silent = True)
os.remove(tmpfile)
m = re.search("#error\W+(\w+)", compiler_output)
if m:
return m.group(1)
except OSError:
pass
log.debug("SIMD detection failed")
return None
#==============================================================================
parse_patterns = (
{'name': "cmake_home", 'default': None, 'pattern': re.compile(r"^CMAKE_HOME_DIRECTORY:INTERNAL=(.+)$")},
{'name': "opencv_home", 'default': None, 'pattern': re.compile(r"^OpenCV_SOURCE_DIR:STATIC=(.+)$")},
{'name': "opencv_build", 'default': None, 'pattern': re.compile(r"^OpenCV_BINARY_DIR:STATIC=(.+)$")},
{'name': "tests_dir", 'default': None, 'pattern': re.compile(r"^EXECUTABLE_OUTPUT_PATH:PATH=(.+)$")},
{'name': "build_type", 'default': "Release", 'pattern': re.compile(r"^CMAKE_BUILD_TYPE:STRING=(.*)$")},
{'name': "git_executable", 'default': None, 'pattern': re.compile(r"^GIT_EXECUTABLE:FILEPATH=(.*)$")},
{'name': "cxx_flags", 'default': "", 'pattern': re.compile(r"^CMAKE_CXX_FLAGS:STRING=(.*)$")},
{'name': "cxx_flags_debug", 'default': "", 'pattern': re.compile(r"^CMAKE_CXX_FLAGS_DEBUG:STRING=(.*)$")},
{'name': "cxx_flags_release", 'default': "", 'pattern': re.compile(r"^CMAKE_CXX_FLAGS_RELEASE:STRING=(.*)$")},
{'name': "opencv_cxx_flags", 'default': "", 'pattern': re.compile(r"^OPENCV_EXTRA_C_FLAGS:INTERNAL=(.*)$")},
{'name': "cxx_flags_android", 'default': None, 'pattern': re.compile(r"^ANDROID_CXX_FLAGS:INTERNAL=(.*)$")},
{'name': "android_abi", 'default': None, 'pattern': re.compile(r"^ANDROID_ABI:STRING=(.*)$")},
{'name': "android_executable", 'default': None, 'pattern': re.compile(r"^ANDROID_EXECUTABLE:FILEPATH=(.*android.*)$")},
{'name': "ant_executable", 'default': None, 'pattern': re.compile(r"^ANT_EXECUTABLE:FILEPATH=(.*ant.*)$")},
{'name': "java_test_binary_dir", 'default': None, 'pattern': re.compile(r"^opencv_test_java_BINARY_DIR:STATIC=(.*)$")},
{'name': "is_x64", 'default': "OFF", 'pattern': re.compile(r"^CUDA_64_BIT_DEVICE_CODE:BOOL=(ON)$")},#ugly(
{'name': "cmake_generator", 'default': None, 'pattern': re.compile(r"^CMAKE_GENERATOR:INTERNAL=(.+)$")},
{'name': "cxx_compiler", 'default': None, 'pattern': re.compile(r"^CMAKE_CXX_COMPILER:\w*PATH=(.+)$")},
{'name': "cxx_compiler_arg1", 'default': None, 'pattern': re.compile(r"^CMAKE_CXX_COMPILER_ARG1:[A-Z]+=(.+)$")},
{'name': "with_cuda", 'default': "OFF", 'pattern': re.compile(r"^WITH_CUDA:BOOL=(ON)$")},
{'name': "cuda_library", 'default': None, 'pattern': re.compile(r"^CUDA_CUDA_LIBRARY:FILEPATH=(.+)$")},
{'name': "cuda_version", 'default': None, 'pattern': re.compile(r"^CUDA_VERSION:STRING=(.+)$")},
{'name': "core_dependencies", 'default': None, 'pattern': re.compile(r"^opencv_core_LIB_DEPENDS:STATIC=(.+)$")},
)
class CMakeCache:
def __init__(self):
self.setDefaultAttrs()
self.cmake_home_vcver = None
self.opencv_home_vcver = None
self.featuresSIMD = None
self.main_modules = []
def setDummy(self, path):
self.tests_dir = os.path.normpath(path)
def read(self, path, fname, cfg):
rx = re.compile(r'^opencv_(\w+)_SOURCE_DIR:STATIC=(.*)$')
module_paths = {} # name -> path
with open(fname, "rt") as cachefile:
for l in cachefile.readlines():
ll = l.strip()
if not ll or ll.startswith("#"):
continue
for p in parse_patterns:
match = p["pattern"].match(ll)
if match:
value = match.groups()[0]
if value and not value.endswith("-NOTFOUND"):
setattr(self, p["name"], value)
# log.debug("cache value: %s = %s", p["name"], value)
match = rx.search(ll)
if match:
module_paths[match.group(1)] = match.group(2)
if not self.tests_dir:
self.tests_dir = path
else:
rel = os.path.relpath(self.tests_dir, self.opencv_build)
self.tests_dir = os.path.join(path, rel)
self.tests_dir = os.path.normpath(self.tests_dir)
# fix VS test binary path (add Debug or Release)
if "Visual Studio" in self.cmake_generator:
if cfg:
self.tests_dir = os.path.join(self.tests_dir, self.options.configuration)
else:
self.tests_dir = os.path.join(self.tests_dir, self.build_type)
self.cmake_home_vcver = readGitVersion(self.git_executable, self.cmake_home)
if self.opencv_home == self.cmake_home:
self.opencv_home_vcver = self.cmake_home_vcver
else:
self.opencv_home_vcver = readGitVersion(self.git_executable, self.opencv_home)
for module,path in module_paths.items():
rel = os.path.relpath(path, self.opencv_home)
if not ".." in rel:
self.main_modules.append(module)
self.flags = [
self.cxx_flags_android,
self.cxx_flags,
self.cxx_flags_release,
self.opencv_cxx_flags,
self.cxx_flags_release]
self.flags = [f for f in self.flags if f]
self.featuresSIMD = testSIMD(self.cxx_compiler, self.flags, self.cxx_compiler_arg1)
def setDefaultAttrs(self):
for p in parse_patterns:
setattr(self, p["name"], p["default"])
def gatherTests(self, mask, isGood = None):
if self.tests_dir and os.path.isdir(self.tests_dir):
d = os.path.abspath(self.tests_dir)
files = glob.glob(os.path.join(d, mask))
if not self.getOS() == "android" and self.withJava():
files.append("java")
return [f for f in files if isGood(f)]
return []
def isMainModule(self, name):
return name in self.main_modules
def withCuda(self):
return self.cuda_version and self.with_cuda == "ON" and self.cuda_library and not self.cuda_library.endswith("-NOTFOUND")
def withJava(self):
return self.ant_executable and self.java_test_binary_dir
def getGitVersion(self):
if self.cmake_home_vcver:
if self.cmake_home_vcver == self.opencv_home_vcver:
rev = self.cmake_home_vcver
elif self.opencv_home_vcver:
rev = self.cmake_home_vcver + "-" + self.opencv_home_vcver
else:
rev = self.cmake_home_vcver
else:
rev = None
if rev:
rev = rev.replace(":","to")
else:
rev = ""
return rev
def getTestFullName(self, shortname):
return os.path.join(self.tests_dir, shortname)
def getSIMDFeatures(self):
return self.featuresSIMD
def getOS(self):
if self.android_executable:
return "android"
else:
return hostos
def getArch(self):
arch = "unknown"
if self.getOS() == "android":
if "armeabi-v7a" in self.android_abi:
arch = "armv7a"
elif "armeabi-v6" in self.android_abi:
arch = "armv6"
elif "armeabi" in self.android_abi:
arch = "armv5te"
elif "x86" in self.android_abi:
arch = "x86"
elif "mips" in self.android_abi:
arch = "mips"
else:
arch = "ARM"
elif self.is_x64 and hostmachine in ["AMD64", "x86_64"]:
arch = "x64"
elif hostmachine in ["x86", "AMD64", "x86_64"]:
arch = "x86"
return arch
def getDependencies(self):
if self.core_dependencies:
candidates = ["tbb", "ippicv", "ipp", "pthreads"]
return [a for a in self.core_dependencies.split(";") if a and a in candidates]
return []
#==============================================================================
def getRunningProcessExePathByName_win32(name):
from ctypes import windll, POINTER, pointer, Structure, sizeof
from ctypes import c_long , c_int , c_uint , c_char , c_ubyte , c_char_p , c_void_p
class PROCESSENTRY32(Structure):
_fields_ = [ ( 'dwSize' , c_uint ) ,
( 'cntUsage' , c_uint) ,
( 'th32ProcessID' , c_uint) ,
( 'th32DefaultHeapID' , c_uint) ,
( 'th32ModuleID' , c_uint) ,
( 'cntThreads' , c_uint) ,
( 'th32ParentProcessID' , c_uint) ,
( 'pcPriClassBase' , c_long) ,
( 'dwFlags' , c_uint) ,
( 'szExeFile' , c_char * 260 ) ,
( 'th32MemoryBase' , c_long) ,
( 'th32AccessKey' , c_long ) ]
class MODULEENTRY32(Structure):
_fields_ = [ ( 'dwSize' , c_long ) ,
( 'th32ModuleID' , c_long ),
( 'th32ProcessID' , c_long ),
( 'GlblcntUsage' , c_long ),
( 'ProccntUsage' , c_long ) ,
( 'modBaseAddr' , c_long ) ,
( 'modBaseSize' , c_long ) ,
( 'hModule' , c_void_p ) ,
( 'szModule' , c_char * 256 ),
( 'szExePath' , c_char * 260 ) ]
TH32CS_SNAPPROCESS = 2
TH32CS_SNAPMODULE = 0x00000008
## CreateToolhelp32Snapshot
CreateToolhelp32Snapshot= windll.kernel32.CreateToolhelp32Snapshot
CreateToolhelp32Snapshot.reltype = c_long
CreateToolhelp32Snapshot.argtypes = [ c_int , c_int ]
## Process32First
Process32First = windll.kernel32.Process32First
Process32First.argtypes = [ c_void_p , POINTER( PROCESSENTRY32 ) ]
Process32First.rettype = c_int
## Process32Next
Process32Next = windll.kernel32.Process32Next
Process32Next.argtypes = [ c_void_p , POINTER(PROCESSENTRY32) ]
Process32Next.rettype = c_int
## CloseHandle
CloseHandle = windll.kernel32.CloseHandle
CloseHandle.argtypes = [ c_void_p ]
CloseHandle.rettype = c_int
## Module32First
Module32First = windll.kernel32.Module32First
Module32First.argtypes = [ c_void_p , POINTER(MODULEENTRY32) ]
Module32First.rettype = c_int
hProcessSnap = c_void_p(0)
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS , 0 )
pe32 = PROCESSENTRY32()
pe32.dwSize = sizeof( PROCESSENTRY32 )
ret = Process32First( hProcessSnap , pointer( pe32 ) )
path = None
while ret :
if name + ".exe" == pe32.szExeFile:
hModuleSnap = c_void_p(0)
me32 = MODULEENTRY32()
me32.dwSize = sizeof( MODULEENTRY32 )
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pe32.th32ProcessID )
ret = Module32First( hModuleSnap, pointer(me32) )
path = me32.szExePath
CloseHandle( hModuleSnap )
if path:
break
ret = Process32Next( hProcessSnap, pointer(pe32) )
CloseHandle( hProcessSnap )
return path
def getRunningProcessExePathByName_posix(name):
pids= [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
path = os.readlink(os.path.join('/proc', pid, 'exe'))
if path and path.endswith(name):
return path
except:
pass
def getRunningProcessExePathByName(name):
try:
if hostos == "nt":
return getRunningProcessExePathByName_win32(name)
elif hostos == "posix":
return getRunningProcessExePathByName_posix(name)
else:
return None
except:
return None
class TempEnvDir:
def __init__(self, envname, prefix):
self.envname = envname
self.prefix = prefix
self.saved_name = None
self.new_name = None
def init(self):
self.saved_name = os.environ.get(self.envname)
self.new_name = tempfile.mkdtemp(prefix=self.prefix, dir=self.saved_name or None)
os.environ[self.envname] = self.new_name
def clean(self):
if self.saved_name:
os.environ[self.envname] = self.saved_name
else:
del os.environ[self.envname]
try:
shutil.rmtree(self.new_name)
except:
pass
#===================================================================================================
if __name__ == "__main__":
log.error("This is utility file, please execute run.py script")
{
IPP static init
Memcheck:Cond
fun:ippicvGetCpuFeatures
fun:ippicvStaticInit
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment