1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-02-20 20:09:11 +00:00

Merge pull request #65 from Sticklyman1936/gem5_fixes

gem5 fixes and one AndroidDevice fix
This commit is contained in:
setrofim 2015-12-10 13:31:57 +00:00
commit aae88b8be4
7 changed files with 127 additions and 61 deletions

View File

@ -236,7 +236,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
.. note:: This will get reset on userdata erasure.
"""
return self.execute('settings get secure android_id').strip()
output = self.execute('content query --uri content://settings/secure --projection value --where "name=\'android_id\'"').strip()
return output.split('value=')[-1]
def get_sdk_version(self):
try:

BIN
wlauto/common/bin/arm64/m5 Executable file

Binary file not shown.

BIN
wlauto/common/bin/armeabi/m5 Executable file

Binary file not shown.

View File

@ -0,0 +1,6 @@
The gem5 simulator can be obtained from http://repo.gem5.org/gem5/ and the
corresponding documentation can be found at http://www.gem5.org.
The source for the m5 binaries bundled with Workload Automation (found at
wlauto/common/bin/arm64/m5 and wlauto/common/bin/armeabi/m5) can be found at
util/m5 in the gem5 source at http://repo.gem5.org/gem5/.

View File

@ -26,9 +26,11 @@ import subprocess
import sys
import tarfile
import time
from pexpect import EOF, TIMEOUT
from pexpect import EOF, TIMEOUT, pxssh
from wlauto import settings, Parameter
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import Executable
from wlauto.core import signal as sig
from wlauto.exceptions import DeviceError
from wlauto.utils import ssh, types
@ -112,6 +114,7 @@ class BaseGem5Device(object):
self.gem5 = None
self.gem5_port = -1
self.gem5outdir = os.path.join(settings.output_directory, "gem5")
self.m5_path = 'm5'
self.stdout_file = None
self.stderr_file = None
self.stderr_filename = None
@ -238,9 +241,19 @@ class BaseGem5Device(object):
port = self.gem5_port
# Connect to the gem5 telnet port. Use a short timeout here.
self.sckt = ssh.TelnetConnection()
self.sckt.login(host, 'None', port=port, auto_prompt_reset=False,
login_timeout=10)
attempts = 0
while attempts < 10:
attempts += 1
try:
self.sckt = ssh.TelnetConnection()
self.sckt.login(host, 'None', port=port, auto_prompt_reset=False,
login_timeout=10)
break
except pxssh.ExceptionPxssh:
pass
else:
self.gem5.kill()
raise DeviceError("Failed to connect to the gem5 telnet session.")
self.logger.info("Connected! Waiting for prompt...")
@ -272,14 +285,7 @@ class BaseGem5Device(object):
self.sckt.setecho(False)
self.sync_gem5_shell()
# Try and avoid line wrapping as much as possible. Don't check the error
# codes from these command because some of them WILL fail.
self.gem5_shell('stty columns 1024', check_exit_code=False)
self.gem5_shell('busybox stty columns 1024', check_exit_code=False)
self.gem5_shell('stty cols 1024', check_exit_code=False)
self.gem5_shell('busybox stty cols 1024', check_exit_code=False)
self.gem5_shell('reset', check_exit_code=False)
self.resize_shell()
def get_properties(self, context): # pylint: disable=R0801
""" Get the property files from the device """
@ -323,7 +329,7 @@ class BaseGem5Device(object):
def get_pids_of(self, process_name):
""" Returns a list of PIDs of all processes with the specified name. """
result = self.gem5_shell('ps | busybox grep {}'.format(process_name),
result = self.gem5_shell('ps | {} grep {}'.format(self.busybox, process_name),
check_exit_code=False).strip()
if result and 'not found' not in result and len(result.split('\n')) > 2:
return [int(x.split()[1]) for x in result.split('\n')]
@ -349,9 +355,6 @@ class BaseGem5Device(object):
self.sckt.PROMPT = prompt
def login(self):
pass
def close(self):
if self._logcat_poller:
self._logcat_poller.stop()
@ -360,9 +363,6 @@ class BaseGem5Device(object):
self.logger.warn("Attempt to restart the gem5 device. This is not "
"supported!")
def init(self):
pass
# pylint: disable=unused-argument
def push_file(self, source, dest, **kwargs):
"""
@ -384,8 +384,11 @@ class BaseGem5Device(object):
# Back to the gem5 world
self.gem5_shell("ls -al /mnt/obb/{}".format(filename))
self.gem5_shell("busybox cp /mnt/obb/{} {}".format(filename, dest))
self.gem5_shell("busybox sync")
if self.busybox:
self.gem5_shell("{} cp /mnt/obb/{} {}".format(self.busybox, filename, dest))
else:
self.gem5_shell("cat /mnt/obb/{} > {}".format(filename, dest))
self.gem5_shell("sync")
self.gem5_shell("ls -al {}".format(dest))
self.gem5_shell("ls -al /mnt/obb/")
self.logger.debug("Push complete.")
@ -395,30 +398,20 @@ class BaseGem5Device(object):
"""
Pull a file from the gem5 device using m5 writefile
First, we check the extension of the file to be copied. If the file ends
in .gz, then gem5 wrongly assumes that it should create a gzipped output
stream, which results in a gem5 error. Therefore, we rename the file on
the local device prior to the writefile command when required. Next, the
file is copied to the local directory within the guest as the m5
The file is copied to the local directory within the guest as the m5
writefile command assumes that the file is local. The file is then
written out to the host system using writefile, prior to being moved to
the destination on the host.
"""
filename = os.path.basename(source)
self.logger.debug("Pulling {} from device.".format(filename))
# gem5 assumes that files ending in .gz are gzip-compressed. We need to
# work around this, else gem5 panics on us. Rename the file for use in
# gem5
if filename[-3:] == '.gz':
filename += '.fugem5'
self.logger.debug("pull_file {} {}".format(source, filename))
# We don't check the exit code here because it is non-zero if the source
# and destination are the same. The ls below will cause an error if the
# file was not where we expected it to be.
self.gem5_shell("busybox cp {} {}".format(source, filename), check_exit_code=False)
self.gem5_shell("busybox sync")
self.gem5_shell("{} cp {} {}".format(self.busybox, source, filename),
check_exit_code=False)
self.gem5_shell("sync")
self.gem5_shell("ls -la {}".format(filename))
self.logger.debug('Finished the copy in the simulator')
self.gem5_util("writefile {}".format(filename))
@ -602,7 +595,7 @@ class BaseGem5Device(object):
def gem5_util(self, command):
""" Execute a gem5 utility command using the m5 binary on the device """
self.gem5_shell('/sbin/m5 ' + command)
self.gem5_shell('{} {}'.format(self.m5_path, command))
def sync_gem5_shell(self):
"""
@ -618,6 +611,19 @@ class BaseGem5Device(object):
self.sckt.expect([self.sckt.UNIQUE_PROMPT, self.sckt.PROMPT], timeout=self.delay)
self.sckt.expect([self.sckt.UNIQUE_PROMPT, self.sckt.PROMPT], timeout=self.delay)
def resize_shell(self):
"""
Resize the shell to avoid line wrapping issues.
"""
# Try and avoid line wrapping as much as possible. Don't check the error
# codes from these command because some of them WILL fail.
self.gem5_shell('stty columns 1024', check_exit_code=False)
self.gem5_shell('{} stty columns 1024'.format(self.busybox), check_exit_code=False)
self.gem5_shell('stty cols 1024', check_exit_code=False)
self.gem5_shell('{} stty cols 1024'.format(self.busybox), check_exit_code=False)
self.gem5_shell('reset', check_exit_code=False)
def move_to_temp_dir(self, source):
"""
Move a file to the temporary directory on the host for copying to the
@ -641,10 +647,38 @@ class BaseGem5Device(object):
"""
self.logger.info("Mounting VirtIO device in simulated system")
self.gem5_shell('busybox mkdir -p /mnt/obb')
self.gem5_shell('mkdir -p /mnt/obb')
mount_command = "mount -t 9p -o trans=virtio,version=9p2000.L,aname={} gem5 /mnt/obb".format(self.temp_dir)
if self.platform == 'linux':
self.gem5_shell(mount_command)
else:
self.gem5_shell('busybox {}'.format(mount_command))
self.gem5_shell(mount_command)
def deploy_m5(self, context, force=False):
"""
Deploys the m5 binary to the device and returns the path to the binary
on the device.
:param force: by default, if the binary is already present on the
device, it will not be deployed again. Setting force to
``True`` overrides that behaviour and ensures that the
binary is always copied. Defaults to ``False``.
:returns: The on-device path to the m5 binary.
"""
on_device_executable = self.path.join(self.binaries_directory, 'm5')
if not force and self.file_exists(on_device_executable):
# We want to check the version of the binary. We cannot directly
# check this because the m5 binary itself is unversioned. We also
# need to make sure not to check the error code as "m5 --help"
# returns a non-zero error code.
output = self.gem5_shell('m5 --help', check_exit_code=False)
if "writefile" in output:
self.logger.debug("Using the m5 binary on the device...")
self.m5_path = on_device_executable
return on_device_executable
else:
self.logger.debug("m5 on device does not support writefile!")
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'm5'))
self.logger.info("Installing the m5 binary to the device...")
self.m5_path = self.install(host_file)
return self.m5_path

View File

@ -71,8 +71,6 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
* m5 binary. Please make sure that the m5 binary is on the device and
can by found in the path.
* Busybox. Due to restrictions, we assume that busybox is installed in
the guest system, and can be found in the path.
"""
name = 'gem5_android'
@ -95,15 +93,27 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
pass
def wait_for_boot(self):
"""
Wait for the system to boot
We monitor the sys.boot_completed and service.bootanim.exit system
properties to determine when the system has finished booting. In the
event that we cannot coerce the result of service.bootanim.exit to an
integer, we assume that the boot animation was disabled and do not wait
for it to finish.
"""
self.logger.info("Waiting for Android to boot...")
while True:
booted = False
anim_finished = True # Assume boot animation was disabled on except
try:
booted = (int('0' + self.gem5_shell('getprop sys.boot_completed', check_exit_code=False)) == 1)
anim_finished = (int('0' + self.gem5_shell('getprop service.bootanim.exit', check_exit_code=False)) == 1)
if booted and anim_finished:
break
except (DeviceError, ValueError):
booted = (int('0' + self.gem5_shell('getprop sys.boot_completed', check_exit_code=False).strip()) == 1)
anim_finished = (int(self.gem5_shell('getprop service.bootanim.exit', check_exit_code=False).strip()) == 1)
except ValueError:
pass
if booted and anim_finished:
break
time.sleep(60)
self.logger.info("Android booted")
@ -133,8 +143,8 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
self.push_file(filepath, on_device_path)
# We need to make sure that the folder permissions are set
# correctly, else the APK does not install correctly.
self.gem5_shell('busybox chmod 775 /data/local/tmp')
self.gem5_shell('busybox chmod 774 {}'.format(on_device_path))
self.gem5_shell('chmod 775 /data/local/tmp')
self.gem5_shell('chmod 774 {}'.format(on_device_path))
self.logger.debug("Actually installing the APK: {}".format(on_device_path))
return self.gem5_shell("pm install {}".format(on_device_path))
else:
@ -146,8 +156,11 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
on_device_file = self.path.join(self.working_directory, executable_name)
on_device_executable = self.path.join(self.binaries_directory, executable_name)
self.push_file(filepath, on_device_file)
self.execute('busybox cp {} {}'.format(on_device_file, on_device_executable))
self.execute('busybox chmod 0777 {}'.format(on_device_executable))
if self.busybox:
self.execute('{} cp {} {}'.format(self.busybox, on_device_file, on_device_executable))
else:
self.execute('cat {} > {}'.format(on_device_file, on_device_executable))
self.execute('chmod 0777 {}'.format(on_device_executable))
return on_device_executable
def uninstall(self, package):
@ -203,3 +216,7 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
# If we didn't manage to do the above, call the parent class.
self.logger.warning("capture_screen: falling back to parent class implementation")
AndroidDevice.capture_screen(self, filepath)
def initialize(self, context):
self.resize_shell()
self.deploy_m5(context, force=False)

View File

@ -19,6 +19,7 @@ import logging
from wlauto import LinuxDevice, Parameter
from wlauto.common.gem5.device import BaseGem5Device
from wlauto.utils import types
class Gem5LinuxDevice(BaseGem5Device, LinuxDevice):
@ -68,8 +69,6 @@ class Gem5LinuxDevice(BaseGem5Device, LinuxDevice):
* m5 binary. Please make sure that the m5 binary is on the device and
can by found in the path.
* Busybox. Due to restrictions, we assume that busybox is installed in
the guest system, and can be found in the path.
"""
name = 'gem5_linux'
@ -80,6 +79,11 @@ class Gem5LinuxDevice(BaseGem5Device, LinuxDevice):
Parameter('core_clusters', default=[], override=True),
Parameter('host', default='localhost', override=True,
description='Host name or IP address for the device.'),
Parameter('login_prompt', kind=types.list_of_strs,
default=['login:', 'AEL login:', 'username:'],
mandatory=False),
Parameter('login_password_prompt', kind=types.list_of_strs,
default=['password:'], mandatory=False),
]
# Overwritten from Device. For documentation, see corresponding method in
@ -92,14 +96,14 @@ class Gem5LinuxDevice(BaseGem5Device, LinuxDevice):
def login_to_device(self):
# Wait for the login prompt
i = self.sckt.expect([r'login:', r'username:', self.sckt.UNIQUE_PROMPT],
timeout=10)
prompt = self.login_prompt + [self.sckt.UNIQUE_PROMPT]
i = self.sckt.expect(prompt, timeout=10)
# Check if we are already at a prompt, or if we need to log in.
if i < 2:
if i < len(prompt) - 1:
self.sckt.sendline("{}".format(self.username))
j = self.sckt.expect([r'password:', r'# ', self.sckt.UNIQUE_PROMPT],
timeout=self.delay)
if j == 2:
password_prompt = self.login_password_prompt + [r'# ', self.sckt.UNIQUE_PROMPT]
j = self.sckt.expect(password_prompt, timeout=self.delay)
if j < len(password_prompt) - 2:
self.sckt.sendline("{}".format(self.password))
self.sckt.expect([r'# ', self.sckt.UNIQUE_PROMPT], timeout=self.delay)
@ -110,3 +114,7 @@ class Gem5LinuxDevice(BaseGem5Device, LinuxDevice):
# If we didn't manage to do the above, call the parent class.
self.logger.warning("capture_screen: falling back to parent class implementation")
LinuxDevice.capture_screen(self, filepath)
def initialize(self, context):
self.resize_shell()
self.deploy_m5(context, force=False)