зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1646368 - Add performance tuning feature to android layer. r=mozperftest-reviewers,tarek
This patch ports the performance tuning functionality from Raptor to mozperftest and adds a small test for it. Differential Revision: https://phabricator.services.mozilla.com/D80168
This commit is contained in:
Родитель
966189d812
Коммит
b1676248ea
|
@ -8,6 +8,7 @@ from pathlib import Path
|
|||
import mozlog
|
||||
from mozdevice import ADBDevice, ADBError
|
||||
from mozperftest.layers import Layer
|
||||
from mozperftest.system.android_perf_tuner import tune_performance
|
||||
from mozperftest.utils import download_file
|
||||
|
||||
|
||||
|
@ -85,6 +86,14 @@ class AndroidDevice(Layer):
|
|||
"default": None,
|
||||
"help": "Captures the logcat to the provided path.",
|
||||
},
|
||||
"perf-tuning": {
|
||||
"action": "store_true",
|
||||
"default": False,
|
||||
"help": (
|
||||
"If set, device will be tuned for performance. "
|
||||
"This helps with decreasing the noise."
|
||||
),
|
||||
},
|
||||
"intent": {"type": str, "default": None, "help": "Intent to use"},
|
||||
"activity": {"type": str, "default": None, "help": "Activity to use"},
|
||||
"install-apk": {
|
||||
|
@ -183,6 +192,9 @@ class AndroidDevice(Layer):
|
|||
if not self.device.is_app_installed(self.app_name):
|
||||
raise Exception("%s is not installed" % self.app_name)
|
||||
|
||||
if self.get_arg("android-perf-tuning", False):
|
||||
tune_performance(self.device)
|
||||
|
||||
# set up default activity with the app name if none given
|
||||
if self.android_activity is None:
|
||||
# guess the activity, given the app
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
def tune_performance(device, log=None, timeout=None):
|
||||
"""Set various performance-oriented parameters, to reduce jitter.
|
||||
|
||||
This includes some device-specific kernel tweaks.
|
||||
|
||||
For more information, see https://bugzilla.mozilla.org/show_bug.cgi?id=1547135.
|
||||
"""
|
||||
PerformanceTuner(device, log=log, timeout=timeout).tune_performance()
|
||||
|
||||
|
||||
class PerformanceTuner:
|
||||
def __init__(self, device, log=None, timeout=None):
|
||||
self.device = device
|
||||
self.log = log is not None and log or self.device._logger
|
||||
self.timeout = timeout
|
||||
|
||||
def tune_performance(self):
|
||||
self.log.info("tuning android device performance")
|
||||
self.set_svc_power_stayon()
|
||||
if self.device._have_su or self.device._have_android_su:
|
||||
device_name = self.device.shell_output(
|
||||
"getprop ro.product.model", timeout=self.timeout
|
||||
)
|
||||
# all commands require root shell from here on
|
||||
self.set_scheduler()
|
||||
self.set_virtual_memory_parameters()
|
||||
self.turn_off_services()
|
||||
self.set_cpu_performance_parameters(device_name)
|
||||
self.set_gpu_performance_parameters(device_name)
|
||||
self.set_kernel_performance_parameters()
|
||||
self.device.clear_logcat(timeout=self.timeout)
|
||||
self.log.info("android device performance tuning complete")
|
||||
|
||||
def _set_value_and_check_exitcode(self, file_name, value, root=False):
|
||||
self.log.info("setting {} to {}".format(file_name, value))
|
||||
if self.device.shell_bool(
|
||||
" ".join(["echo", str(value), ">", str(file_name)]),
|
||||
root=root,
|
||||
timeout=self.timeout,
|
||||
):
|
||||
self.log.info("successfully set {} to {}".format(file_name, value))
|
||||
else:
|
||||
self.log.warning("command failed")
|
||||
|
||||
def set_svc_power_stayon(self):
|
||||
self.log.info("set device to stay awake on usb")
|
||||
self.device.shell_bool("svc power stayon usb", timeout=self.timeout)
|
||||
|
||||
def set_scheduler(self):
|
||||
self.log.info("setting scheduler to noop")
|
||||
scheduler_location = "/sys/block/sda/queue/scheduler"
|
||||
|
||||
self._set_value_and_check_exitcode(scheduler_location, "noop")
|
||||
|
||||
def turn_off_services(self):
|
||||
services = [
|
||||
"mpdecision",
|
||||
"thermal-engine",
|
||||
"thermald",
|
||||
]
|
||||
for service in services:
|
||||
self.log.info(" ".join(["turning off service:", service]))
|
||||
self.device.shell_bool(
|
||||
" ".join(["stop", service]), root=True, timeout=self.timeout
|
||||
)
|
||||
|
||||
services_list_output = self.device.shell_output(
|
||||
"service list", timeout=self.timeout
|
||||
)
|
||||
for service in services:
|
||||
if service not in services_list_output:
|
||||
self.log.info(" ".join(["successfully terminated:", service]))
|
||||
else:
|
||||
self.log.warning(" ".join(["failed to terminate:", service]))
|
||||
|
||||
def disable_animations(self):
|
||||
self.log.info("disabling animations")
|
||||
commands = {
|
||||
"animator_duration_scale": 0.0,
|
||||
"transition_animation_scale": 0.0,
|
||||
"window_animation_scale": 0.0,
|
||||
}
|
||||
|
||||
for key, value in commands.items():
|
||||
command = " ".join(["settings", "put", "global", key, str(value)])
|
||||
self.log.info("setting {} to {}".format(key, value))
|
||||
self.device.shell_bool(command, timeout=self.timeout)
|
||||
|
||||
def restore_animations(self):
|
||||
# animation settings are not restored to default by reboot
|
||||
self.log.info("restoring animations")
|
||||
commands = {
|
||||
"animator_duration_scale": 1.0,
|
||||
"transition_animation_scale": 1.0,
|
||||
"window_animation_scale": 1.0,
|
||||
}
|
||||
|
||||
for key, value in commands.items():
|
||||
command = " ".join(["settings", "put", "global", key, str(value)])
|
||||
self.device.shell_bool(command, timeout=self.timeout)
|
||||
|
||||
def set_virtual_memory_parameters(self):
|
||||
self.log.info("setting virtual memory parameters")
|
||||
commands = {
|
||||
"/proc/sys/vm/swappiness": 0,
|
||||
"/proc/sys/vm/dirty_ratio": 85,
|
||||
"/proc/sys/vm/dirty_background_ratio": 70,
|
||||
}
|
||||
|
||||
for key, value in commands.items():
|
||||
self._set_value_and_check_exitcode(key, value, root=True)
|
||||
|
||||
def set_cpu_performance_parameters(self, device_name=None):
|
||||
self.log.info("setting cpu performance parameters")
|
||||
commands = {}
|
||||
|
||||
if device_name is not None:
|
||||
device_name = self.device.shell_output(
|
||||
"getprop ro.product.model", timeout=self.timeout
|
||||
)
|
||||
|
||||
if device_name == "Pixel 2":
|
||||
# MSM8998 (4x 2.35GHz, 4x 1.9GHz)
|
||||
# values obtained from:
|
||||
# /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
|
||||
# /sys/devices/system/cpu/cpufreq/policy4/scaling_available_frequencies
|
||||
commands.update(
|
||||
{
|
||||
"/sys/devices/system/cpu/cpufreq/policy0/scaling_governor": "performance",
|
||||
"/sys/devices/system/cpu/cpufreq/policy4/scaling_governor": "performance",
|
||||
"/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq": "1900800",
|
||||
"/sys/devices/system/cpu/cpufreq/policy4/scaling_min_freq": "2457600",
|
||||
}
|
||||
)
|
||||
elif device_name == "Moto G (5)":
|
||||
# MSM8937(8x 1.4GHz)
|
||||
# values obtained from:
|
||||
# /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
|
||||
for x in range(0, 8):
|
||||
commands.update(
|
||||
{
|
||||
"/sys/devices/system/cpu/cpu{}/"
|
||||
"cpufreq/scaling_governor".format(x): "performance",
|
||||
"/sys/devices/system/cpu/cpu{}/"
|
||||
"cpufreq/scaling_min_freq".format(x): "1401000",
|
||||
}
|
||||
)
|
||||
else:
|
||||
self.log.info(
|
||||
"CPU for device with ro.product.model '{}' unknown, not scaling_governor".format(
|
||||
device_name
|
||||
)
|
||||
)
|
||||
|
||||
for key, value in commands.items():
|
||||
self._set_value_and_check_exitcode(key, value, root=True)
|
||||
|
||||
def set_gpu_performance_parameters(self, device_name=None):
|
||||
self.log.info("setting gpu performance parameters")
|
||||
commands = {
|
||||
"/sys/class/kgsl/kgsl-3d0/bus_split": "0",
|
||||
"/sys/class/kgsl/kgsl-3d0/force_bus_on": "1",
|
||||
"/sys/class/kgsl/kgsl-3d0/force_rail_on": "1",
|
||||
"/sys/class/kgsl/kgsl-3d0/force_clk_on": "1",
|
||||
"/sys/class/kgsl/kgsl-3d0/force_no_nap": "1",
|
||||
"/sys/class/kgsl/kgsl-3d0/idle_timer": "1000000",
|
||||
}
|
||||
|
||||
if not device_name:
|
||||
device_name = self.device.shell_output(
|
||||
"getprop ro.product.model", timeout=self.timeout
|
||||
)
|
||||
|
||||
if device_name == "Pixel 2":
|
||||
# Adreno 540 (710MHz)
|
||||
# values obtained from:
|
||||
# /sys/devices/soc/5000000.qcom,kgsl-3d0/kgsl/kgsl-3d0/max_clk_mhz
|
||||
commands.update(
|
||||
{
|
||||
"/sys/devices/soc/5000000.qcom,kgsl-3d0/devfreq/"
|
||||
"5000000.qcom,kgsl-3d0/governor": "performance",
|
||||
"/sys/devices/soc/soc:qcom,kgsl-busmon/devfreq/"
|
||||
"soc:qcom,kgsl-busmon/governor": "performance",
|
||||
"/sys/devices/soc/5000000.qcom,kgsl-3d0/kgsl/kgsl-3d0/min_clock_mhz": "710",
|
||||
}
|
||||
)
|
||||
elif device_name == "Moto G (5)":
|
||||
# Adreno 505 (450MHz)
|
||||
# values obtained from:
|
||||
# /sys/devices/soc/1c00000.qcom,kgsl-3d0/kgsl/kgsl-3d0/max_clock_mhz
|
||||
commands.update(
|
||||
{
|
||||
"/sys/devices/soc/1c00000.qcom,kgsl-3d0/devfreq/"
|
||||
"1c00000.qcom,kgsl-3d0/governor": "performance",
|
||||
"/sys/devices/soc/1c00000.qcom,kgsl-3d0/kgsl/kgsl-3d0/min_clock_mhz": "450",
|
||||
}
|
||||
)
|
||||
else:
|
||||
self.log.info(
|
||||
"GPU for device with ro.product.model '{}' unknown, not setting devfreq".format(
|
||||
device_name
|
||||
)
|
||||
)
|
||||
|
||||
for key, value in commands.items():
|
||||
self._set_value_and_check_exitcode(key, value, root=True)
|
||||
|
||||
def set_kernel_performance_parameters(self):
|
||||
self.log.info("setting kernel performance parameters")
|
||||
commands = {
|
||||
"/sys/kernel/debug/msm-bus-dbg/shell-client/update_request": "1",
|
||||
"/sys/kernel/debug/msm-bus-dbg/shell-client/mas": "1",
|
||||
"/sys/kernel/debug/msm-bus-dbg/shell-client/ab": "0",
|
||||
"/sys/kernel/debug/msm-bus-dbg/shell-client/slv": "512",
|
||||
}
|
||||
for key, value in commands.items():
|
||||
self._set_value_and_check_exitcode(key, value, root=True)
|
|
@ -6,12 +6,25 @@ from unittest import mock
|
|||
from mozperftest.tests.support import get_running_env, requests_content, temp_file
|
||||
from mozperftest.environment import SYSTEM
|
||||
from mozperftest.system.android import DeviceError
|
||||
from mozperftest.system.android_perf_tuner import PerformanceTuner
|
||||
from mozperftest.utils import silence
|
||||
|
||||
|
||||
class FakeDevice:
|
||||
def __init__(self, **args):
|
||||
self.apps = []
|
||||
self._logger = mock.MagicMock()
|
||||
self._have_su = True
|
||||
self._have_android_su = True
|
||||
|
||||
def clear_logcat(self, *args, **kwargs):
|
||||
return True
|
||||
|
||||
def shell_output(self, *args, **kwargs):
|
||||
return "A Fake Device"
|
||||
|
||||
def shell_bool(self, *args, **kwargs):
|
||||
return True
|
||||
|
||||
def uninstall_app(self, apk_name):
|
||||
return True
|
||||
|
@ -41,6 +54,57 @@ def test_android():
|
|||
android(metadata)
|
||||
|
||||
|
||||
@mock.patch("mozperftest.system.android.ADBLoggedDevice")
|
||||
def test_android_perf_tuning_rooted(device):
|
||||
# Check to make sure that performance tuning runs
|
||||
# on rooted devices correctly
|
||||
device._have_su = True
|
||||
device._have_android_su = True
|
||||
with mock.patch(
|
||||
"mozperftest.system.android_perf_tuner.PerformanceTuner.set_kernel_performance_parameters"
|
||||
) as mockfunc:
|
||||
tuner = PerformanceTuner(device)
|
||||
tuner.tune_performance()
|
||||
mockfunc.assert_called()
|
||||
|
||||
|
||||
@mock.patch("mozperftest.system.android.ADBLoggedDevice")
|
||||
def test_android_perf_tuning_nonrooted(device):
|
||||
# Check to make sure that performance tuning runs
|
||||
# on non-rooted devices correctly
|
||||
device._have_su = False
|
||||
device._have_android_su = False
|
||||
with mock.patch(
|
||||
"mozperftest.system.android_perf_tuner.PerformanceTuner.set_kernel_performance_parameters"
|
||||
) as mockfunc:
|
||||
tuner = PerformanceTuner(device)
|
||||
tuner.tune_performance()
|
||||
mockfunc.assert_not_called()
|
||||
|
||||
|
||||
@mock.patch("mozperftest.system.android_perf_tuner.PerformanceTuner")
|
||||
@mock.patch("mozperftest.system.android.ADBLoggedDevice")
|
||||
def test_android_with_perftuning(device, tuner):
|
||||
args = {
|
||||
"flavor": "mobile-browser",
|
||||
"android-install-apk": ["this.apk"],
|
||||
"android": True,
|
||||
"android-timeout": 30,
|
||||
"android-capture-adb": "stdout",
|
||||
"android-app-name": "org.mozilla.fenix",
|
||||
"android-perf-tuning": True,
|
||||
}
|
||||
tuner.return_value = tuner
|
||||
|
||||
mach_cmd, metadata, env = get_running_env(**args)
|
||||
system = env.layers[SYSTEM]
|
||||
with system as android, silence(system):
|
||||
android(metadata)
|
||||
|
||||
# Make sure the tuner was actually called
|
||||
tuner.tune_performance.assert_called()
|
||||
|
||||
|
||||
def test_android_failure():
|
||||
# no patching so it'll try for real and fail
|
||||
args = {
|
||||
|
|
|
@ -77,12 +77,14 @@ jobs:
|
|||
--android-activity org.mozilla.fenix.IntentReceiverActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--android-perf-tuning
|
||||
--perfherder-metrics processLaunchToNavStart
|
||||
--android-install-apk fenix_nightlysim_multicommit_armeabi_v7a
|
||||
--hooks testing/performance/hooks_applink.py
|
||||
--perfherder
|
||||
--perfherder-app fenix
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 10
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--verbose
|
||||
testing/performance/perftest_applink.js
|
||||
|
@ -108,10 +110,12 @@ jobs:
|
|||
--android-activity org.mozilla.fenix.IntentReceiverActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--android-perf-tuning
|
||||
--hooks testing/performance/hooks_applink.py
|
||||
--perfherder
|
||||
--perfherder-app fenix
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 10
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--verbose
|
||||
testing/performance/perftest_applink.js
|
||||
|
@ -135,12 +139,14 @@ jobs:
|
|||
--android-activity org.mozilla.geckoview_example.GeckoViewActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--android-perf-tuning
|
||||
--perfherder-metrics processLaunchToNavStart
|
||||
--android-install-apk gve_nightly_api16
|
||||
--hooks testing/performance/hooks_applink.py
|
||||
--perfherder
|
||||
--perfherder-app geckoview
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 10
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--verbose
|
||||
testing/performance/perftest_applink.js
|
||||
|
@ -164,12 +170,14 @@ jobs:
|
|||
--android-capture-logcat logcat
|
||||
--android-app-name org.mozilla.geckoview_example
|
||||
--android-activity org.mozilla.geckoview_example.GeckoViewActivity
|
||||
--android-perf-tuning
|
||||
--perfherder-metrics processLaunchToNavStart
|
||||
--android-install-apk gve_nightly_api16
|
||||
--hooks testing/performance/hooks_applink.py
|
||||
--perfherder
|
||||
--perfherder-app geckoview
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 10
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--verbose
|
||||
testing/performance/perftest_applink.js
|
||||
|
|
Загрузка…
Ссылка в новой задаче