Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / build / android / pylib / perf / perf_control.py
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import atexit
6 import logging
7
8 from pylib import android_commands
9 from pylib.device import device_utils
10
11 class PerfControl(object):
12   """Provides methods for setting the performance mode of a device."""
13   _SCALING_GOVERNOR_FMT = (
14       '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor')
15   _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online'
16   _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
17
18   def __init__(self, device):
19     # TODO(jbudorick) Remove once telemetry gets switched over.
20     if isinstance(device, android_commands.AndroidCommands):
21       device = device_utils.DeviceUtils(device)
22     self._device = device
23     cpu_files = self._device.RunShellCommand(
24       'ls -d /sys/devices/system/cpu/cpu[0-9]*')
25     self._num_cpu_cores = len(cpu_files)
26     assert self._num_cpu_cores > 0, 'Failed to detect CPUs.'
27     logging.info('Number of CPUs: %d', self._num_cpu_cores)
28     self._have_mpdecision = self._device.FileExists('/system/bin/mpdecision')
29
30   def SetHighPerfMode(self):
31     """Sets the highest stable performance mode for the device."""
32     if not self._device.old_interface.IsRootEnabled():
33       message = 'Need root for performance mode. Results may be NOISY!!'
34       logging.warning(message)
35       # Add an additional warning at exit, such that it's clear that any results
36       # may be different/noisy (due to the lack of intended performance mode).
37       atexit.register(logging.warning, message)
38       return
39
40     product_model = self._device.old_interface.GetProductModel()
41     # TODO(epenner): Enable on all devices (http://crbug.com/383566)
42     if 'Nexus 4' == product_model:
43       self._ForceAllCpusOnline(True)
44       if not self._AllCpusAreOnline():
45         logging.warning('Failed to force CPUs online. Results may be NOISY!')
46       self._SetScalingGovernorInternal('performance')
47     elif 'Nexus 5' == product_model:
48       self._ForceAllCpusOnline(True)
49       if not self._AllCpusAreOnline():
50         logging.warning('Failed to force CPUs online. Results may be NOISY!')
51       self._SetScalingGovernorInternal('performance')
52       self._SetScalingMaxFreq(1190400)
53       self._SetMaxGpuClock(200000000)
54     else:
55       self._SetScalingGovernorInternal('performance')
56
57   def SetPerfProfilingMode(self):
58     """Enables all cores for reliable perf profiling."""
59     self._ForceAllCpusOnline(True)
60     self._SetScalingGovernorInternal('performance')
61     if not self._AllCpusAreOnline():
62       if not self._device.old_interface.IsRootEnabled():
63         raise RuntimeError('Need root to force CPUs online.')
64       raise RuntimeError('Failed to force CPUs online.')
65
66   def SetDefaultPerfMode(self):
67     """Sets the performance mode for the device to its default mode."""
68     if not self._device.old_interface.IsRootEnabled():
69       return
70     product_model = self._device.old_interface.GetProductModel()
71     if 'Nexus 5' == product_model:
72       if self._AllCpusAreOnline():
73         self._SetScalingMaxFreq(2265600)
74         self._SetMaxGpuClock(450000000)
75
76     governor_mode = {
77         'GT-I9300': 'pegasusq',
78         'Galaxy Nexus': 'interactive',
79         'Nexus 4': 'ondemand',
80         'Nexus 5': 'ondemand',
81         'Nexus 7': 'interactive',
82         'Nexus 10': 'interactive'
83     }.get(product_model, 'ondemand')
84     self._SetScalingGovernorInternal(governor_mode)
85     self._ForceAllCpusOnline(False)
86
87   def _SetScalingGovernorInternal(self, value):
88     cpu_cores = ' '.join([str(x) for x in range(self._num_cpu_cores)])
89     script = ('for CPU in %s; do\n'
90         '  FILE="/sys/devices/system/cpu/cpu$CPU/cpufreq/scaling_governor"\n'
91         '  test -e $FILE && echo %s > $FILE\n'
92         'done\n') % (cpu_cores, value)
93     logging.info('Setting scaling governor mode: %s', value)
94     self._device.RunShellCommand(script, as_root=True)
95
96   def _SetScalingMaxFreq(self, value):
97     cpu_cores = ' '.join([str(x) for x in range(self._num_cpu_cores)])
98     script = ('for CPU in %s; do\n'
99         '  FILE="/sys/devices/system/cpu/cpu$CPU/cpufreq/scaling_max_freq"\n'
100         '  test -e $FILE && echo %d > $FILE\n'
101         'done\n') % (cpu_cores, value)
102     self._device.RunShellCommand(script, as_root=True)
103
104   def _SetMaxGpuClock(self, value):
105     self._device.WriteFile('/sys/class/kgsl/kgsl-3d0/max_gpuclk',
106                            str(value),
107                            as_root=True)
108
109   def _AllCpusAreOnline(self):
110     for cpu in range(1, self._num_cpu_cores):
111       online_path = PerfControl._CPU_ONLINE_FMT % cpu
112       # TODO(epenner): Investigate why file may be missing
113       # (http://crbug.com/397118)
114       if not self._device.FileExists(online_path) or \
115             self._device.ReadFile(online_path)[0] == '0':
116         return False
117     return True
118
119   def _ForceAllCpusOnline(self, force_online):
120     """Enable all CPUs on a device.
121
122     Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise
123     to measurements:
124     - In perf, samples are only taken for the CPUs that are online when the
125       measurement is started.
126     - The scaling governor can't be set for an offline CPU and frequency scaling
127       on newly enabled CPUs adds noise to both perf and tracing measurements.
128
129     It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm
130     this is done by "mpdecision".
131
132     """
133     if self._have_mpdecision:
134       script = 'stop mpdecision' if force_online else 'start mpdecision'
135       self._device.RunShellCommand(script, as_root=True)
136
137     if not self._have_mpdecision and not self._AllCpusAreOnline():
138       logging.warning('Unexpected cpu hot plugging detected.')
139
140     if not force_online:
141       return
142
143     for cpu in range(self._num_cpu_cores):
144       online_path = PerfControl._CPU_ONLINE_FMT % cpu
145       self._device.WriteFile(online_path, '1', as_root=True)
146