Index: tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py |
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py |
index 49ecc7cca0f79d2629f1bc42c7131419ac09476b..53ff8af68d2637f416d2600a313274a56b35ca23 100644 |
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py |
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py |
@@ -12,7 +12,7 @@ import tempfile |
from telemetry.core import util |
from telemetry.core.platform import profiler |
-from telemetry.core.platform.profiler import android_prebuilt_profiler_helper |
+from telemetry.core.platform.profiler import android_profiling_helper |
class _SingleProcessPerfProfiler(object): |
@@ -21,7 +21,8 @@ class _SingleProcessPerfProfiler(object): |
On android, this profiler uses pre-built binaries from AOSP. |
See more details in prebuilt/android/README.txt. |
""" |
- def __init__(self, pid, output_file, browser_backend, platform_backend): |
+ def __init__(self, pid, output_file, browser_backend, platform_backend, |
+ perf_binary): |
self._pid = pid |
self._browser_backend = browser_backend |
self._platform_backend = platform_backend |
@@ -30,8 +31,6 @@ class _SingleProcessPerfProfiler(object): |
self._is_android = platform_backend.GetOSName() == 'android' |
cmd_prefix = [] |
if self._is_android: |
- perf_binary = android_prebuilt_profiler_helper.GetDevicePath( |
- 'perf') |
cmd_prefix = ['adb', '-s', browser_backend.adb.device_serial(), 'shell', |
perf_binary] |
output_file = os.path.join('/sdcard', 'perf_profiles', |
@@ -39,8 +38,9 @@ class _SingleProcessPerfProfiler(object): |
self._device_output_file = output_file |
browser_backend.adb.RunShellCommand( |
'mkdir -p ' + os.path.dirname(self._device_output_file)) |
+ browser_backend.adb.RunShellCommand('rm -f ' + self._device_output_file) |
else: |
- cmd_prefix = ['perf'] |
+ cmd_prefix = [perf_binary] |
# In perf 3.13 --call-graph requires an argument, so use |
# the -g short-hand which does not. |
self._proc = subprocess.Popen(cmd_prefix + |
@@ -79,81 +79,30 @@ Try rerunning this script under sudo or setting |
self._tmp_output_file.close() |
cmd = 'perf report -n -i %s' % self._output_file |
if self._is_android: |
- print 'On Android, assuming $CHROMIUM_OUT_DIR/Release/lib has a fresh' |
- print 'symbolized library matching the one on device.' |
+ device = self._browser_backend.adb.device() |
+ device.old_interface.Adb().Pull(self._device_output_file, |
+ self._output_file) |
+ required_libs = \ |
+ android_profiling_helper.GetRequiredLibrariesForPerfProfile( |
+ self._output_file) |
+ symfs_root = os.path.dirname(self._output_file) |
+ kallsyms = android_profiling_helper.CreateSymFs(device, |
+ symfs_root, |
+ required_libs, |
+ use_symlinks=True) |
+ cmd += ' --symfs %s --kallsyms %s' % (symfs_root, kallsyms) |
+ |
objdump_path = os.path.join(os.environ.get('ANDROID_TOOLCHAIN', |
'$ANDROID_TOOLCHAIN'), |
'arm-linux-androideabi-objdump') |
print 'If you have recent version of perf (3.10+), append the following ' |
print 'to see annotated source code (by pressing the \'a\' key): ' |
print ' --objdump %s' % objdump_path |
- cmd += ' ' + ' '.join(self._PrepareAndroidSymfs()) |
+ |
print 'To view the profile, run:' |
print ' ', cmd |
return self._output_file |
- def _PrepareAndroidSymfs(self): |
- """Create a symfs directory using an Android device. |
- |
- Create a symfs directory by pulling the necessary files from an Android |
- device. |
- |
- Returns: |
- List of arguments to be passed to perf to point it to the created symfs. |
- """ |
- assert self._is_android |
- device = self._browser_backend.adb.device() |
- device.old_interface.Adb().Pull(self._device_output_file, self._output_file) |
- symfs_dir = os.path.dirname(self._output_file) |
- host_app_symfs = os.path.join(symfs_dir, 'data', 'app-lib') |
- if not os.path.exists(host_app_symfs): |
- os.makedirs(host_app_symfs) |
- # On Android, the --symfs parameter needs to map a directory structure |
- # similar to the device, that is: |
- # --symfs=/tmp/foobar and then inside foobar there'll be something like |
- # /tmp/foobar/data/app-lib/$PACKAGE/libname.so |
- # Assume the symbolized library under out/Release/lib is equivalent to |
- # the one in the device, and symlink it in the host to match --symfs. |
- device_dir = filter( |
- lambda app_lib: app_lib.startswith(self._browser_backend.package), |
- device.old_interface.RunShellCommand('ls /data/app-lib')) |
- os.symlink(os.path.abspath( |
- os.path.join(util.GetChromiumSrcDir(), |
- os.environ.get('CHROMIUM_OUT_DIR', 'out'), |
- 'Release', 'lib')), |
- os.path.join(host_app_symfs, device_dir[0])) |
- |
- # Also pull copies of common system libraries from the device so perf can |
- # resolve their symbols. Only copy a subset of libraries to make this |
- # faster. |
- # TODO(skyostil): Find a way to pull in all system libraries without being |
- # too slow. |
- host_system_symfs = os.path.join(symfs_dir, 'system', 'lib') |
- if not os.path.exists(host_system_symfs): |
- os.makedirs(host_system_symfs) |
- common_system_libs = [ |
- 'libandroid*.so', |
- 'libart.so', |
- 'libc.so', |
- 'libdvm.so', |
- 'libEGL*.so', |
- 'libGL*.so', |
- 'libm.so', |
- 'libRS.so', |
- 'libskia.so', |
- 'libstdc++.so', |
- 'libstlport.so', |
- 'libz.so', |
- ] |
- for lib in common_system_libs: |
- device.old_interface.Adb().Pull('/system/lib/%s' % lib, |
- host_system_symfs) |
- # Pull a copy of the kernel symbols. |
- host_kallsyms = os.path.join(symfs_dir, 'kallsyms') |
- if not os.path.exists(host_kallsyms): |
- device.old_interface.Adb().Pull('/proc/kallsyms', host_kallsyms) |
- return ['--kallsyms', host_kallsyms, '--symfs', symfs_dir] |
- |
def _GetStdOut(self): |
self._tmp_output_file.flush() |
try: |
@@ -170,18 +119,17 @@ class PerfProfiler(profiler.Profiler): |
browser_backend, platform_backend, output_path, state) |
process_output_file_map = self._GetProcessOutputFileMap() |
self._process_profilers = [] |
+ perf_binary = 'perf' |
if platform_backend.GetOSName() == 'android': |
- android_prebuilt_profiler_helper.InstallOnDevice( |
- browser_backend.adb.device(), 'perf') |
- # Make sure kernel pointers are not hidden. |
- browser_backend.adb.device().old_interface.SetProtectedFileContents( |
- '/proc/sys/kernel/kptr_restrict', '0') |
+ perf_binary = android_profiling_helper.PrepareDeviceForPerf( |
+ browser_backend.adb.device()) |
+ |
for pid, output_file in process_output_file_map.iteritems(): |
if 'zygote' in output_file: |
continue |
self._process_profilers.append( |
_SingleProcessPerfProfiler( |
- pid, output_file, browser_backend, platform_backend)) |
+ pid, output_file, browser_backend, platform_backend, perf_binary)) |
@classmethod |
def name(cls): |