Bug 1547135 - reduce tp6m test result jitter for Android (Pixel 2) r=jmaher,acreskey,rwood
authorEdwin Gao <egao@mozilla.com>
Thu, 09 May 2019 16:35:27 +0000
changeset 473261 44f3132aaed8ac51661a9cf5ba53b5c949f6d6b3
parent 473260 bc29b6ed69e821515c82490a5c2afb5019d8f115
child 473262 804d239e671bc7572641c0c864fa7a147c338b3e
push id85123
push useregao@mozilla.com
push dateThu, 09 May 2019 16:36:22 +0000
treeherderautoland@44f3132aaed8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher, acreskey, rwood
bugs1547135
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1547135 - reduce tp6m test result jitter for Android (Pixel 2) r=jmaher,acreskey,rwood All changes are reversible upon reboot, with exception of the animation setting which is restored to default settings once Raptor concludes testing. All values are for Pixel 2. Motorola G5 patch will be available separately. Changes: - set cpu/gpu to `performance` mode, and override minimum frequency with the maximum available frequency - tweak msm-bus related kernel settings - set display to be permanently on when connected over USB - disable animation for duration of test - turn off thermal throttling Differential Revision: https://phabricator.services.mozilla.com/D30116
testing/raptor/raptor/raptor.py
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -659,16 +659,169 @@ class RaptorAndroid(Raptor):
 
     def create_browser_handler(self):
         # create the android device handler; it gets initiated and sets up adb etc
         self.log.info("creating android device handler using mozdevice")
         self.device = ADBDevice(verbose=True)
         self.device.clear_logcat()
         self.clear_app_data()
 
+    def tune_performance(self):
+        """Sets various performance-oriented parameters, to reduce jitter.
+
+        For more information, see https://bugzilla.mozilla.org/show_bug.cgi?id=1547135.
+        """
+        self.log.info("tuning android device performance")
+        self.set_scheduler()
+        self.set_svc_power_stayon()
+        device_name = self.device.shell_output('getprop ro.product.model')
+        if (self.device._have_su or self.device._have_android_su):
+            # all commands require root shell from here on
+            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()
+
+    def _set_value_and_check_exitcode(self, file_name, value):
+        self.log.info('setting {} to {}'.format(file_name, value))
+        process = self.device.shell(' '.join(['echo', str(value), '>', str(file_name)]), root=True)
+        if process.exitcode == 0:
+            self.log.info('successfully set {} to {}'.format(file_name, value))
+        else:
+            self.log.warning('command failed with exitcode {}'.format(str(process.exitcode)))
+
+    def set_svc_power_stayon(self):
+        self.log.info('set device to stay awake on usb')
+        self.device.shell('svc power stayon usb')
+
+    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(' '.join(['stop', service]), root=True)
+
+        services_list_output = self.device.shell_output('service list')
+        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(command)
+
+    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(command)
+
+    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):
+        self.log.info('setting cpu performance parameters')
+        commands = {}
+
+        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)':
+            pass
+        else:
+            pass
+
+        for key, value in commands.items():
+            self._set_value_and_check_exitcode(key, value)
+
+    def set_gpu_performance_parameters(self, device_name):
+        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 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)':
+            pass
+        else:
+            pass
+        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)
+
     def clear_app_data(self):
         self.log.info("clearing %s app data" % self.config['binary'])
         self.device.shell("pm clear %s" % self.config['binary'])
 
     def create_raptor_sdcard_folder(self):
         # for android/geckoview, create a top-level raptor folder on the device
         # sdcard; if it already exists remove it so we start fresh each time
         self.device_raptor_dir = "/sdcard/raptor"
@@ -983,16 +1136,19 @@ def main(args=sys.argv[1:]):
                           post_startup_delay=args.post_startup_delay,
                           activity=args.activity,
                           intent=args.intent,
                           interrupt_handler=SignalHandler(),
                           )
 
     raptor.create_browser_profile()
     raptor.create_browser_handler()
+    if type(raptor) == RaptorAndroid:
+        # only Raptor Android supports device performance tuning
+        raptor.tune_performance()
     raptor.start_control_server()
 
     try:
         for next_test in raptor_test_list:
             raptor.run_test(next_test, timeout=int(next_test['page_timeout']))
 
         success = raptor.process_results(raptor_test_names)