Support parallel build and install in on-device apk scripts.
Add -p flag to build.py to build native libs in parallel. Add -p
flag to install.py to install to multiple devices in parallel.
Change-Id: I042de5eae321e61455d330949c7f07577725ba15
diff --git a/android/scripts/build.py b/android/scripts/build.py
index 3e42371..1fb54e8 100644
--- a/android/scripts/build.py
+++ b/android/scripts/build.py
@@ -53,9 +53,8 @@
# Make build directory if necessary
if not os.path.exists(buildDir):
os.makedirs(buildDir)
- os.chdir(buildDir)
toolchainFile = '%s/framework/delibs/cmake/toolchain-android-%s.cmake' % (deqpDir, common.ANDROID_NDK_TOOLCHAIN_VERSION)
- common.execArgs([
+ common.execArgsInDirectory([
'cmake',
'-G%s' % common.CMAKE_GENERATOR,
'-DCMAKE_TOOLCHAIN_FILE=%s' % toolchainFile,
@@ -66,10 +65,9 @@
'-DCMAKE_BUILD_TYPE=%s' % buildType,
'-DDEQP_TARGET=android',
deqpDir
- ])
+ ], buildDir)
- os.chdir(buildDir)
- common.execArgs(['cmake', '--build', '.'] + common.EXTRA_BUILD_ARGS)
+ common.execArgsInDirectory(['cmake', '--build', '.'] + common.EXTRA_BUILD_ARGS, buildDir)
if not os.path.exists(libsDir):
os.makedirs(libsDir)
@@ -138,7 +136,7 @@
'bin/dEQP-release.apk'
])
-def build (buildRoot=common.ANDROID_DIR, isRelease=False, nativeBuildType="Release", javaApi=common.ANDROID_JAVA_API):
+def build (buildRoot=common.ANDROID_DIR, isRelease=False, nativeBuildType="Release", javaApi=common.ANDROID_JAVA_API, doParallelBuild=False):
curDir = os.getcwd()
try:
@@ -159,8 +157,11 @@
shutil.rmtree(libTargetDir)
# Build native code
- for lib in common.NATIVE_LIBS:
- buildNative(buildRoot, libTargetDir, lib, nativeBuildType)
+ nativeBuildArgs = [(buildRoot, libTargetDir, nativeLib, nativeBuildType) for nativeLib in common.NATIVE_LIBS]
+ if doParallelBuild:
+ common.parallelApply(buildNative, nativeBuildArgs)
+ else:
+ common.serialApply(buildNative, nativeBuildArgs)
# Copy assets
if os.path.exists(assetsSrcDir):
@@ -186,10 +187,11 @@
parser.add_argument('--build-root', dest='buildRoot', default=common.ANDROID_DIR, help="Root directory for storing build results.")
parser.add_argument('--dump-config', dest='dumpConfig', action='store_true', help="Print out all configurations variables")
parser.add_argument('--java-api', dest='javaApi', default=common.ANDROID_JAVA_API, help="Set the API signature for the java build.")
+ parser.add_argument('-p', '--parallel-build', dest='parallelBuild', action="store_true", help="Build native libraries in parallel.")
args = parser.parse_args()
if args.dumpConfig:
dumpConfig()
- build(buildRoot=os.path.abspath(args.buildRoot), isRelease=args.isRelease, nativeBuildType=args.nativeBuildType, javaApi=args.javaApi)
+ build(buildRoot=os.path.abspath(args.buildRoot), isRelease=args.isRelease, nativeBuildType=args.nativeBuildType, javaApi=args.javaApi, doParallelBuild=args.parallelBuild)
diff --git a/android/scripts/common.py b/android/scripts/common.py
index 674d818..d8e5b1b 100644
--- a/android/scripts/common.py
+++ b/android/scripts/common.py
@@ -8,6 +8,11 @@
import multiprocessing
import string
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
class NativeLib:
def __init__ (self, apiVersion, abiVersion):
self.apiVersion = apiVersion
@@ -82,7 +87,43 @@
sys.stdout.flush()
retcode = subprocess.call(args)
if retcode != 0:
- raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
+ raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
+
+def execArgsInDirectory (args, cwd):
+ # Make sure previous stdout prints have been written out.
+ sys.stdout.flush()
+ process = subprocess.Popen(args, cwd=cwd)
+ retcode = process.wait()
+ if retcode != 0:
+ raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
+
+def serialApply(f, argsList):
+ for args in argsList:
+ f(*args)
+
+def parallelApply(f, argsList):
+ class ErrorCode:
+ def __init__ (self):
+ self.error = None;
+
+ def applyAndCaptureError (func, args, errorCode):
+ try:
+ func(*args)
+ except:
+ errorCode.error = sys.exc_info()
+
+ errorCode = ErrorCode()
+ jobs = []
+ for args in argsList:
+ job = threading.Thread(target=applyAndCaptureError, args=(f, args, errorCode))
+ job.start()
+ jobs.append(job)
+
+ for job in jobs:
+ job.join()
+
+ if errorCode.error:
+ raise errorCode.error[0], errorCode.error[1], errorCode.error[2]
class Device:
def __init__(self, serial, product, model, device):
@@ -99,7 +140,7 @@
(stdout, stderr) = proc.communicate()
if proc.returncode != 0:
- raise Exception("adb devices -l failed, got %d" % retcode)
+ raise Exception("adb devices -l failed, got %d" % proc.returncode)
ptrn = re.compile(r'^([a-zA-Z0-9]+)\s+.*product:([^\s]+)\s+model:([^\s]+)\s+device:([^\s]+)')
devices = []
diff --git a/android/scripts/install.py b/android/scripts/install.py
index 2ef02cd..317dd84 100644
--- a/android/scripts/install.py
+++ b/android/scripts/install.py
@@ -7,43 +7,39 @@
import common
-def install (extraArgs = []):
- curDir = os.getcwd()
- try:
- os.chdir(common.ANDROID_DIR)
+def install (extraArgs = [], printPrefix=""):
+ print printPrefix + "Removing old dEQP Package...\n",
+ common.execArgsInDirectory([common.ADB_BIN] + extraArgs + [
+ 'uninstall',
+ 'com.drawelements.deqp'
+ ], common.ANDROID_DIR)
+ print printPrefix + "Remove complete\n",
- print "Removing old dEQP Package..."
- common.execArgs([common.ADB_BIN] + extraArgs + [
- 'uninstall',
- 'com.drawelements.deqp'
- ])
- print ""
+ print printPrefix + "Installing dEQP Package...\n",
+ common.execArgsInDirectory([common.ADB_BIN] + extraArgs + [
+ 'install',
+ '-r',
+ 'package/bin/dEQP-debug.apk'
+ ], common.ANDROID_DIR)
+ print printPrefix + "Install complete\n",
- print "Installing dEQP Package..."
- common.execArgs([common.ADB_BIN] + extraArgs + [
- 'install',
- '-r',
- 'package/bin/dEQP-debug.apk'
- ])
- print ""
+def installToDevice (device, printPrefix=""):
+ print printPrefix + "Installing to %s (%s)...\n" % (device.serial, device.model),
+ install(['-s', device.serial], printPrefix)
- finally:
- # Restore working dir
- os.chdir(curDir)
-
-def installToDevice (device):
- print "Installing to %s (%s)..." % (device.serial, device.model)
- install(['-s', device.serial])
-
-def installToAllDevices ():
+def installToAllDevices (doParallel):
devices = common.getDevices(common.ADB_BIN)
- for device in devices:
- installToDevice(device)
+ padLen = max([len(device.model) for device in devices])+1
+ if doParallel:
+ common.parallelApply(installToDevice, [(device, ("(%s):%s" % (device.model, ' ' * (padLen - len(device.model))))) for device in devices]);
+ else:
+ common.serialApply(installToDevice, [(device, ) for device in devices]);
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] == '-a':
- installToAllDevices()
+ doParallel = '-p' in sys.argv[1:]
+ installToAllDevices(doParallel)
else:
install(sys.argv[1:])
else: