oeqa/runqemu: Support RUNQEMU_TMPFS_DIR as a location to copy snapshot images to

We have a working theory that IO queues on the autobuilder are impacting
runtime testing under qemu, particularly async writes which inice does not
influence. We already pass the snapshot option to qemu which copies the
image and runs out of the copy. Add in the ability to copy the image to
a specificed location which can be a tmpfs. This means that writes to the
image would no longer be blocked by other writes to disk in the system.

Preliminary tests show that this does improve the qemu errors at the expense
of sometimes showing qemu startup timeouts as on a loaded system with a large
test image, it can take longer than 120s to copy the image to tmpfs. Having
a most consistent failure mode for loaded tests is probably desireable though.

(From OE-Core rev: fd1c26ab426c3699ffd8082b83d65a84c8eb8bff)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Richard Purdie 2021-03-31 22:41:52 +01:00
parent 82d7dc9709
commit 232cb7b055
6 changed files with 24 additions and 4 deletions

View File

@ -305,6 +305,7 @@ def testimage_main(d):
'dump_dir' : d.getVar("TESTIMAGE_DUMP_DIR"),
'serial_ports': len(d.getVar("SERIAL_CONSOLES").split()),
'ovmf' : ovmf,
'tmpfsdir' : d.getVar("RUNQEMU_TMPFS_DIR"),
}
if d.getVar("TESTIMAGE_BOOT_PATTERNS"):

View File

@ -21,7 +21,7 @@ class OEQemuTarget(OESSHTarget):
port=None, machine='', rootfs='', kernel='', kvm=False, slirp=False,
dump_dir='', dump_host_cmds='', display='', bootlog='',
tmpdir='', dir_image='', boottime=60, serial_ports=2,
boot_patterns = defaultdict(str), ovmf=False, **kwargs):
boot_patterns = defaultdict(str), ovmf=False, tmpfsdir=None, **kwargs):
super(OEQemuTarget, self).__init__(logger, None, server_ip, timeout,
user, port)
@ -42,7 +42,7 @@ class OEQemuTarget(OESSHTarget):
use_kvm=kvm, use_slirp=slirp, dump_dir=dump_dir,
dump_host_cmds=dump_host_cmds, logger=logger,
serial_ports=serial_ports, boot_patterns = boot_patterns,
use_ovmf=ovmf)
use_ovmf=ovmf, tmpfsdir=tmpfsdir)
dump_target_cmds = kwargs.get("testimage_dump_target")
self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)
self.target_dumper.create_dir("qemu")

View File

@ -131,6 +131,7 @@ class QemuTarget(BaseTarget):
logfile = self.qemulog,
kernel = self.kernel,
boottime = int(d.getVar("TEST_QEMUBOOT_TIMEOUT")),
tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
logger = logger)
else:
self.runner = QemuRunner(machine=d.getVar("MACHINE"),
@ -144,6 +145,7 @@ class QemuTarget(BaseTarget):
dump_dir = dump_dir,
dump_host_cmds = d.getVar("testimage_dump_host"),
logger = logger,
tmpfsdir = d.getVar("RUNQEMU_TMPFS_DIR"),
serial_ports = len(d.getVar("SERIAL_CONSOLES").split()))
self.target_dumper = TargetDumper(dump_target_cmds, dump_dir, self.runner)

View File

@ -32,7 +32,7 @@ re_control_char = re.compile('[%s]' % re.escape("".join(control_chars)))
class QemuRunner:
def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, dump_host_cmds,
use_kvm, logger, use_slirp=False, serial_ports=2, boot_patterns = defaultdict(str), use_ovmf=False, workdir=None):
use_kvm, logger, use_slirp=False, serial_ports=2, boot_patterns = defaultdict(str), use_ovmf=False, workdir=None, tmpfsdir=None):
# Popen object for runqemu
self.runqemu = None
@ -61,6 +61,7 @@ class QemuRunner:
self.serial_ports = serial_ports
self.msg = ''
self.boot_patterns = boot_patterns
self.tmpfsdir = tmpfsdir
self.runqemutime = 120
if not workdir:
@ -150,6 +151,9 @@ class QemuRunner:
else:
env["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image
if self.tmpfsdir:
env["RUNQEMU_TMPFS_DIR"] = self.tmpfsdir
if not launch_cmd:
launch_cmd = 'runqemu %s' % ('snapshot' if discard_writes else '')
if self.use_kvm:

View File

@ -19,7 +19,7 @@ from .qemurunner import QemuRunner
class QemuTinyRunner(QemuRunner):
def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, kernel, boottime, logger):
def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, kernel, boottime, logger, tmpfsdir=None):
# Popen object for runqemu
self.runqemu = None
@ -37,6 +37,7 @@ class QemuTinyRunner(QemuRunner):
self.deploy_dir_image = deploy_dir_image
self.logfile = logfile
self.boottime = boottime
self.tmpfsdir = tmpfsdir
self.runqemutime = 60
self.socketfile = "console.sock"
@ -83,6 +84,9 @@ class QemuTinyRunner(QemuRunner):
return False
else:
os.environ["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image
if self.tmpfsdir:
env["RUNQEMU_TMPFS_DIR"] = self.tmpfsdir
# Set this flag so that Qemu doesn't do any grabs as SDL grabs interact
# badly with screensavers.

View File

@ -1196,6 +1196,15 @@ class BaseConfig(object):
self.fstype = self.fstype[4:]
rootfs_format = self.fstype if self.fstype in ('vmdk', 'vhd', 'vhdx', 'qcow2', 'vdi') else 'raw'
tmpfsdir = os.environ.get("RUNQEMU_TMPFS_DIR", None)
if self.snapshot and tmpfsdir:
newrootfs = os.path.join(tmpfsdir, os.path.basename(self.rootfs)) + "." + str(os.getpid())
shutil.copyfile(self.rootfs, newrootfs)
#print("Copying rootfs to tmpfs: %s" % newrootfs)
self.rootfs = newrootfs
# Don't need a second copy now!
self.snapshot = False
qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
if qb_rootfs_opt:
self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)