# 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/. from mozdevice import ADBError 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(object): def __init__(self, device, log=None, timeout=None): self.device = device self.log = 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.is_rooted: 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): self.log.info("setting {} to {}".format(file_name, value)) try: self.device.shell_output( " ".join(["echo", str(value), ">", str(file_name)]), timeout=self.timeout, ) self.log.info("successfully set {} to {}".format(file_name, value)) except ADBError as e: self.log.info( "Ignoring failure to set value {} to {}. {}".format(file_name, value, e) ) 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: try: self.log.info(" ".join(["turning off service:", service])) self.device.shell_bool( " ".join(["stop", service]), timeout=self.timeout ) except ADBError as e: self.log.info( "Ignoring failure to stop service {}. Error: {}: {}".format( service, e.__class__.__name__, e ) ) 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) def set_cpu_performance_parameters(self, device_name=None): self.log.info("setting cpu performance parameters") commands = {} if not device_name: device_name = self.device.shell_output( "getprop ro.product.model", timeout=self.timeout ) # Samsung A51 perf tuning: Bug 1876543 # Pixel 6 perf tuning: Bug 1876545 # Samsung S21 perf tuning: Bug 1876546 if device_name == "SM-A515F": 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": "1742000", "/sys/devices/system/cpu/cpufreq/policy4/scaling_min_freq": "2314000", } ) 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) 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 ) # Samsung A51 perf tuning: Bug 1876543 # Pixel 6 perf tuning: Bug 1876545 # Samsung S21 perf tuning: Bug 1876546 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) 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)