Commit e2beb407 authored by Stephen Roe's avatar Stephen Roe Committed by Commit Bot

[fuchsia] add option to retry test environment setup steps.

Also adds debug logging for qemu-img invocations in the qemu target.

Bug: 1046861
Change-Id: Ia37a9701391e3437cf03f1f041ddca671d5e0770
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2023387
Commit-Queue: Stephen Roe <steveroe@google.com>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740058}
parent 47af615b
...@@ -17,7 +17,7 @@ class AemuTarget(qemu_target.QemuTarget): ...@@ -17,7 +17,7 @@ class AemuTarget(qemu_target.QemuTarget):
hardware_gpu): hardware_gpu):
super(AemuTarget, self).__init__(output_dir, target_cpu, system_log_file, super(AemuTarget, self).__init__(output_dir, target_cpu, system_log_file,
emu_type, cpu_cores, require_kvm, emu_type, cpu_cores, require_kvm,
ram_size_mb) ram_size_mb, qemu_img_retries=0)
# TODO(crbug.com/1000907): Enable AEMU for arm64. # TODO(crbug.com/1000907): Enable AEMU for arm64.
if platform.machine() == 'aarch64': if platform.machine() == 'aarch64':
......
...@@ -155,6 +155,7 @@ def GetDeploymentTargetForArgs(args, require_kvm=False): ...@@ -155,6 +155,7 @@ def GetDeploymentTargetForArgs(args, require_kvm=False):
'emu_type':args.device, 'emu_type':args.device,
'ram_size_mb':args.memory }) 'ram_size_mb':args.memory })
if args.device == 'qemu': if args.device == 'qemu':
target_args.update({ 'qemu_img_retries':args.qemu_img_retries })
return QemuTarget(**target_args) return QemuTarget(**target_args)
else: else:
target_args.update({ target_args.update({
......
...@@ -15,6 +15,7 @@ import shutil ...@@ -15,6 +15,7 @@ import shutil
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import time
from common import GetEmuRootForPlatform, EnsurePathExists from common import GetEmuRootForPlatform, EnsurePathExists
...@@ -28,16 +29,19 @@ GUEST_MAC_ADDRESS = '52:54:00:63:5e:7b' ...@@ -28,16 +29,19 @@ GUEST_MAC_ADDRESS = '52:54:00:63:5e:7b'
# Capacity of the system's blobstore volume. # Capacity of the system's blobstore volume.
EXTENDED_BLOBSTORE_SIZE = 1073741824 # 1GB EXTENDED_BLOBSTORE_SIZE = 1073741824 # 1GB
# qemu-img p99 run time is 26 seconds. Using 2x the p99 time as the timeout.
QEMU_IMG_TIMEOUT_SEC = 52
class QemuTarget(emu_target.EmuTarget): class QemuTarget(emu_target.EmuTarget):
def __init__(self, output_dir, target_cpu, system_log_file, def __init__(self, output_dir, target_cpu, system_log_file,
emu_type, cpu_cores, require_kvm, ram_size_mb): emu_type, cpu_cores, require_kvm, ram_size_mb, qemu_img_retries):
super(QemuTarget, self).__init__(output_dir, target_cpu, super(QemuTarget, self).__init__(output_dir, target_cpu,
system_log_file) system_log_file)
self._emu_type=emu_type self._emu_type=emu_type
self._cpu_cores=cpu_cores self._cpu_cores=cpu_cores
self._require_kvm=require_kvm self._require_kvm=require_kvm
self._ram_size_mb=ram_size_mb self._ram_size_mb=ram_size_mb
self._qemu_img_retries=qemu_img_retries
def _GetEmulatorName(self): def _GetEmulatorName(self):
return self._emu_type return self._emu_type
...@@ -71,7 +75,8 @@ class QemuTarget(emu_target.EmuTarget): ...@@ -71,7 +75,8 @@ class QemuTarget(emu_target.EmuTarget):
'-snapshot', '-snapshot',
'-drive', 'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' % '-drive', 'file=%s,format=qcow2,if=none,id=blobstore,snapshot=on' %
_EnsureBlobstoreQcowAndReturnPath(self._output_dir, _EnsureBlobstoreQcowAndReturnPath(self._output_dir,
self._GetTargetSdkArch()), self._GetTargetSdkArch(),
self._qemu_img_retries),
'-device', 'virtio-blk-pci,drive=blobstore', '-device', 'virtio-blk-pci,drive=blobstore',
# Use stdio for the guest OS only; don't attach the QEMU interactive # Use stdio for the guest OS only; don't attach the QEMU interactive
...@@ -148,6 +153,7 @@ class QemuTarget(emu_target.EmuTarget): ...@@ -148,6 +153,7 @@ class QemuTarget(emu_target.EmuTarget):
qemu_command.append('-nographic') qemu_command.append('-nographic')
return qemu_command return qemu_command
def _ComputeFileHash(filename): def _ComputeFileHash(filename):
hasher = md5.new() hasher = md5.new()
with open(filename, 'rb') as f: with open(filename, 'rb') as f:
...@@ -159,12 +165,69 @@ def _ComputeFileHash(filename): ...@@ -159,12 +165,69 @@ def _ComputeFileHash(filename):
return hasher.hexdigest() return hasher.hexdigest()
def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch): def _ExecWithTimeout(command, timeout_sec):
"""Execute command in subprocess with timeout.
Has debug logging for run time measurements.
Returns: None if command timed out or return code if command completed.
"""
p = subprocess.Popen(command)
start_sec = time.time()
num_checks = 0
while p.poll() is None and time.time() - start_sec < timeout_sec:
time.sleep(1)
num_checks += 1
stop_sec = time.time()
# Sleep durations are much less than 1 second for python2.7 on arm64
# Logging number of checks and total duration to help debug timeouts.
logging.debug('qemu_target sleep checks: %d' % num_checks)
logging.debug('qemu_target sleep start: %f' % start_sec)
logging.debug('qemu_target sleep stop: %f' % stop_sec)
logging.debug('qemu_target sleep duration: %f' % float(stop_sec - start_sec))
if p.poll() is None:
p.kill()
return None
return p.returncode
def _ExecWithTimeoutAndRetry(command, timeout_sec, retries):
""" Execute command in subprocess with timeout and retries.
Raises CalledProcessError if command does not complete successfully.
"""
try:
tries = 0
status = None
while status is None and tries <= retries:
tries += 1
logging.debug('qemu_target call: %s' % command)
status = _ExecWithTimeout(command, timeout_sec)
logging.debug('qemu_target done: %s' % command[0])
if status is None:
raise subprocess.CalledProcessError(-1, command)
if status:
raise subprocess.CalledProcessError(status, command)
except subprocess.CalledProcessError as error:
logging.debug(
'qemu_target._EnsureBlobStoreQcowAndReturnPath qemu_img error: %s' %
error)
raise
def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch,
qemu_img_retries):
"""Returns a file containing the Fuchsia blobstore in a QCOW format, """Returns a file containing the Fuchsia blobstore in a QCOW format,
with extra buffer space added for growth.""" with extra buffer space added for growth."""
qimg_tool = os.path.join(common.GetEmuRootForPlatform('qemu'), qemu_img_tool = os.path.join(common.GetEmuRootForPlatform('qemu'),
'bin', 'qemu-img') 'bin', 'qemu-img')
fvm_tool = common.GetHostToolPathFromPlatform('fvm') fvm_tool = common.GetHostToolPathFromPlatform('fvm')
blobstore_path = boot_data.GetTargetFile('storage-full.blk', target_arch, blobstore_path = boot_data.GetTargetFile('storage-full.blk', target_arch,
'qemu') 'qemu')
...@@ -193,8 +256,10 @@ def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch): ...@@ -193,8 +256,10 @@ def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch):
# Construct a QCOW image from the extended, temporary FVM volume. # Construct a QCOW image from the extended, temporary FVM volume.
# The result will be retained in the build output directory for re-use. # The result will be retained in the build output directory for re-use.
subprocess.check_call([qimg_tool, 'convert', '-f', 'raw', '-O', 'qcow2', # TODO(crbug.com/1046861): Remove retries after qemu-img bug is fixed.
'-c', extended_blobstore.name, qcow_path]) qemu_img_cmd = [qemu_img_tool, 'convert', '-f', 'raw', '-O', 'qcow2',
'-c', extended_blobstore.name, qcow_path]
_ExecWithTimeoutAndRetry(qemu_img_cmd, QEMU_IMG_TIMEOUT_SEC, qemu_img_retries)
# Write out a hash of the original blobstore file, so that subsequent runs # Write out a hash of the original blobstore file, so that subsequent runs
# can trivially check if a cached extended FVM volume is available for reuse. # can trivially check if a cached extended FVM volume is available for reuse.
......
...@@ -33,6 +33,13 @@ def main(): ...@@ -33,6 +33,13 @@ def main():
parser.add_argument('--gtest_repeat', parser.add_argument('--gtest_repeat',
help='GTest repeat value to use. This also disables the ' help='GTest repeat value to use. This also disables the '
'test launcher timeout.') 'test launcher timeout.')
# TODO(crbug.com/1046861): Remove qemu-img-retries flag when qemu-img arm64
# hang bug is fixed.
parser.add_argument('--qemu-img-retries',
default=0,
type=int,
help='Number of times that the qemu-img command can be '
'retried.')
parser.add_argument('--test-launcher-retry-limit', parser.add_argument('--test-launcher-retry-limit',
help='Number of times that test suite will retry failing ' help='Number of times that test suite will retry failing '
'tests. This is multiplicative with --gtest_repeat.') 'tests. This is multiplicative with --gtest_repeat.')
......
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