aboutsummaryrefslogtreecommitdiff
path: root/crosperf/suite_runner.py
diff options
context:
space:
mode:
Diffstat (limited to 'crosperf/suite_runner.py')
-rw-r--r--crosperf/suite_runner.py297
1 files changed, 297 insertions, 0 deletions
diff --git a/crosperf/suite_runner.py b/crosperf/suite_runner.py
new file mode 100644
index 00000000..678113a7
--- /dev/null
+++ b/crosperf/suite_runner.py
@@ -0,0 +1,297 @@
+# Copyright (c) 2013~2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""SuiteRunner defines the interface from crosperf to test script."""
+
+from __future__ import print_function
+
+import os
+import time
+import shlex
+
+from cros_utils import command_executer
+import test_flag
+
+TEST_THAT_PATH = '/usr/bin/test_that'
+AUTOTEST_DIR = '~/trunk/src/third_party/autotest/files'
+CHROME_MOUNT_DIR = '/tmp/chrome_root'
+
+
+def GetProfilerArgs(profiler_args):
+ # Remove "--" from in front of profiler args.
+ args_list = shlex.split(profiler_args)
+ new_list = []
+ for arg in args_list:
+ if arg[0:2] == '--':
+ arg = arg[2:]
+ new_list.append(arg)
+ args_list = new_list
+
+ # Remove "perf_options=" from middle of profiler args.
+ new_list = []
+ for arg in args_list:
+ idx = arg.find('perf_options=')
+ if idx != -1:
+ prefix = arg[0:idx]
+ suffix = arg[idx + len('perf_options=') + 1:-1]
+ new_arg = prefix + "'" + suffix + "'"
+ new_list.append(new_arg)
+ else:
+ new_list.append(arg)
+ args_list = new_list
+
+ return ' '.join(args_list)
+
+
+class SuiteRunner(object):
+ """This defines the interface from crosperf to test script."""
+
+ def __init__(self,
+ logger_to_use=None,
+ log_level='verbose',
+ cmd_exec=None,
+ cmd_term=None):
+ self.logger = logger_to_use
+ self.log_level = log_level
+ self._ce = cmd_exec or command_executer.GetCommandExecuter(
+ self.logger, log_level=self.log_level)
+ self._ct = cmd_term or command_executer.CommandTerminator()
+
+ def Run(self, machine, label, benchmark, test_args, profiler_args):
+ for i in range(0, benchmark.retries + 1):
+ self.PinGovernorExecutionFrequencies(machine, label.chromeos_root)
+ if benchmark.suite == 'telemetry':
+ self.DecreaseWaitTime(machine, label.chromeos_root)
+ ret_tup = self.Telemetry_Run(machine, label, benchmark, profiler_args)
+ elif benchmark.suite == 'telemetry_Crosperf':
+ self.DecreaseWaitTime(machine, label.chromeos_root)
+ ret_tup = self.Telemetry_Crosperf_Run(machine, label, benchmark,
+ test_args, profiler_args)
+ else:
+ ret_tup = self.Test_That_Run(machine, label, benchmark, test_args,
+ profiler_args)
+ if ret_tup[0] != 0:
+ self.logger.LogOutput('benchmark %s failed. Retries left: %s' %
+ (benchmark.name, benchmark.retries - i))
+ elif i > 0:
+ self.logger.LogOutput('benchmark %s succeded after %s retries' %
+ (benchmark.name, i))
+ break
+ else:
+ self.logger.LogOutput('benchmark %s succeded on first try' %
+ benchmark.name)
+ break
+ return ret_tup
+
+ def PinGovernorExecutionFrequencies(self, machine_name, chromeos_root):
+ """Set min and max frequencies to max static frequency."""
+ # pyformat: disable
+ set_cpu_freq = (
+ 'set -e && '
+ 'for f in /sys/devices/system/cpu/cpu*/cpufreq; do '
+ 'cd $f; '
+ 'val=0; '
+ 'if [[ -e scaling_available_frequencies ]]; then '
+ # pylint: disable=line-too-long
+ ' val=`cat scaling_available_frequencies | tr " " "\\n" | sort -n -b -r`; '
+ 'else '
+ ' val=`cat scaling_max_freq | tr " " "\\n" | sort -n -b -r`; fi ; '
+ 'set -- $val; '
+ 'highest=$1; '
+ 'if [[ $# -gt 1 ]]; then '
+ ' case $highest in *1000) highest=$2;; esac; '
+ 'fi ;'
+ 'echo $highest > scaling_max_freq; '
+ 'echo $highest > scaling_min_freq; '
+ 'echo performance > scaling_governor; '
+ 'done'
+ )
+ # pyformat: enable
+ if self.log_level == 'average':
+ self.logger.LogOutput('Pinning governor execution frequencies for %s' %
+ machine_name)
+ ret = self._ce.CrosRunCommand(
+ set_cpu_freq, machine=machine_name, chromeos_root=chromeos_root)
+ self.logger.LogFatalIf(ret, 'Could not pin frequencies on machine: %s' %
+ machine_name)
+
+ def DecreaseWaitTime(self, machine_name, chromeos_root):
+ """Change the ten seconds wait time for pagecycler to two seconds."""
+ FILE = '/usr/local/telemetry/src/tools/perf/page_sets/page_cycler_story.py'
+ ret = self._ce.CrosRunCommand(
+ 'ls ' + FILE, machine=machine_name, chromeos_root=chromeos_root)
+ self.logger.LogFatalIf(ret, 'Could not find {} on machine: {}'.format(
+ FILE, machine_name))
+
+ if not ret:
+ sed_command = 'sed -i "s/_TTI_WAIT_TIME = 10/_TTI_WAIT_TIME = 2/g" '
+ ret = self._ce.CrosRunCommand(
+ sed_command + FILE, machine=machine_name, chromeos_root=chromeos_root)
+ self.logger.LogFatalIf(ret, 'Could not modify {} on machine: {}'.format(
+ FILE, machine_name))
+
+ def RebootMachine(self, machine_name, chromeos_root):
+ command = 'reboot && exit'
+ self._ce.CrosRunCommand(
+ command, machine=machine_name, chromeos_root=chromeos_root)
+ time.sleep(60)
+ # Whenever we reboot the machine, we need to restore the governor settings.
+ self.PinGovernorExecutionFrequencies(machine_name, chromeos_root)
+
+ def Test_That_Run(self, machine, label, benchmark, test_args, profiler_args):
+ """Run the test_that test.."""
+ options = ''
+ if label.board:
+ options += ' --board=%s' % label.board
+ if test_args:
+ options += ' %s' % test_args
+ if profiler_args:
+ self.logger.LogFatal('test_that does not support profiler.')
+ command = 'rm -rf /usr/local/autotest/results/*'
+ self._ce.CrosRunCommand(
+ command, machine=machine, chromeos_root=label.chromeos_root)
+
+ # We do this because some tests leave the machine in weird states.
+ # Rebooting between iterations has proven to help with this.
+ self.RebootMachine(machine, label.chromeos_root)
+
+ autotest_dir = AUTOTEST_DIR
+ if label.autotest_path != '':
+ autotest_dir = label.autotest_path
+
+ autotest_dir_arg = '--autotest_dir %s' % autotest_dir
+ # For non-telemetry tests, specify an autotest directory only if the
+ # specified directory is different from default (crosbug.com/679001).
+ if autotest_dir == AUTOTEST_DIR:
+ autotest_dir_arg = ''
+
+ command = (('%s %s --fast '
+ '%s %s %s') % (TEST_THAT_PATH, autotest_dir_arg, options,
+ machine, benchmark.test_name))
+ if self.log_level != 'verbose':
+ self.logger.LogOutput('Running test.')
+ self.logger.LogOutput('CMD: %s' % command)
+ # Use --no-ns-pid so that cros_sdk does not create a different
+ # process namespace and we can kill process created easily by
+ # their process group.
+ return self._ce.ChrootRunCommandWOutput(
+ label.chromeos_root,
+ command,
+ command_terminator=self._ct,
+ cros_sdk_options='--no-ns-pid')
+
+ def RemoveTelemetryTempFile(self, machine, chromeos_root):
+ filename = 'telemetry@%s' % machine
+ fullname = os.path.join(chromeos_root, 'chroot', 'tmp', filename)
+ if os.path.exists(fullname):
+ os.remove(fullname)
+
+ def Telemetry_Crosperf_Run(self, machine, label, benchmark, test_args,
+ profiler_args):
+ if not os.path.isdir(label.chrome_src):
+ self.logger.LogFatal('Cannot find chrome src dir to'
+ ' run telemetry: %s' % label.chrome_src)
+
+ # Check for and remove temporary file that may have been left by
+ # previous telemetry runs (and which might prevent this run from
+ # working).
+ self.RemoveTelemetryTempFile(machine, label.chromeos_root)
+
+ # For telemetry runs, we can use the autotest copy from the source
+ # location. No need to have one under /build/<board>.
+ autotest_dir_arg = '--autotest_dir %s' % AUTOTEST_DIR
+ if label.autotest_path != '':
+ autotest_dir_arg = '--autotest_dir %s' % label.autotest_path
+
+ profiler_args = GetProfilerArgs(profiler_args)
+ fast_arg = ''
+ if not profiler_args:
+ # --fast works unless we are doing profiling (autotest limitation).
+ # --fast avoids unnecessary copies of syslogs.
+ fast_arg = '--fast'
+ args_string = ''
+ if test_args:
+ # Strip double quotes off args (so we can wrap them in single
+ # quotes, to pass through to Telemetry).
+ if test_args[0] == '"' and test_args[-1] == '"':
+ test_args = test_args[1:-1]
+ args_string = "test_args='%s'" % test_args
+
+ cmd = ('{} {} {} --board={} --args="{} run_local={} test={} '
+ '{}" {} telemetry_Crosperf'.format(TEST_THAT_PATH, autotest_dir_arg,
+ fast_arg, label.board,
+ args_string, benchmark.run_local,
+ benchmark.test_name,
+ profiler_args, machine))
+
+ # Use --no-ns-pid so that cros_sdk does not create a different
+ # process namespace and we can kill process created easily by their
+ # process group.
+ chrome_root_options = ('--no-ns-pid '
+ '--chrome_root={} --chrome_root_mount={} '
+ "FEATURES=\"-usersandbox\" "
+ 'CHROME_ROOT={}'.format(label.chrome_src,
+ CHROME_MOUNT_DIR,
+ CHROME_MOUNT_DIR))
+ if self.log_level != 'verbose':
+ self.logger.LogOutput('Running test.')
+ self.logger.LogOutput('CMD: %s' % cmd)
+ return self._ce.ChrootRunCommandWOutput(
+ label.chromeos_root,
+ cmd,
+ command_terminator=self._ct,
+ cros_sdk_options=chrome_root_options)
+
+ def Telemetry_Run(self, machine, label, benchmark, profiler_args):
+ telemetry_run_path = ''
+ if not os.path.isdir(label.chrome_src):
+ self.logger.LogFatal('Cannot find chrome src dir to' ' run telemetry.')
+ else:
+ telemetry_run_path = os.path.join(label.chrome_src, 'src/tools/perf')
+ if not os.path.exists(telemetry_run_path):
+ self.logger.LogFatal('Cannot find %s directory.' % telemetry_run_path)
+
+ if profiler_args:
+ self.logger.LogFatal('Telemetry does not support the perf profiler.')
+
+ # Check for and remove temporary file that may have been left by
+ # previous telemetry runs (and which might prevent this run from
+ # working).
+ if not test_flag.GetTestMode():
+ self.RemoveTelemetryTempFile(machine, label.chromeos_root)
+
+ rsa_key = os.path.join(
+ label.chromeos_root,
+ 'src/scripts/mod_for_test_scripts/ssh_keys/testing_rsa')
+
+ cmd = ('cd {0} && '
+ './run_measurement '
+ '--browser=cros-chrome '
+ '--output-format=csv '
+ '--remote={1} '
+ '--identity {2} '
+ '{3} {4}'.format(telemetry_run_path, machine, rsa_key,
+ benchmark.test_name, benchmark.test_args))
+ if self.log_level != 'verbose':
+ self.logger.LogOutput('Running test.')
+ self.logger.LogOutput('CMD: %s' % cmd)
+ return self._ce.RunCommandWOutput(cmd, print_to_console=False)
+
+ def CommandTerminator(self):
+ return self._ct
+
+ def Terminate(self):
+ self._ct.Terminate()
+
+
+class MockSuiteRunner(object):
+ """Mock suite runner for test."""
+
+ def __init__(self):
+ self._true = True
+
+ def Run(self, *_args):
+ if self._true:
+ return [0, '', '']
+ else:
+ return [0, '', '']