def CollectProfile(self): if ('renderer' in self._output_file and not self._is_android and not self._platform_backend.GetCommandLine(self._pid)): logging.warning('Renderer was swapped out during profiling. ' 'To collect a full profile rerun with ' '"--extra-browser-args=--single-process"') if self._is_android: device = self._browser_backend.device try: binary_name = os.path.basename(self._perf_binary) device.KillAll(binary_name, signum=signal.SIGINT, blocking=True, quiet=True) except device_errors.CommandFailedError: logging.warning( 'The perf process could not be killed on the device.') self._proc.send_signal(signal.SIGINT) exit_code = self._proc.wait() try: if exit_code == 128: raise Exception("""perf failed with exit code 128. Try rerunning this script under sudo or setting /proc/sys/kernel/perf_event_paranoid to "-1".\nOutput:\n%s""" % self._GetStdOut()) elif exit_code not in (0, -2): raise Exception('perf failed with exit code %d. Output:\n%s' % (exit_code, self._GetStdOut())) finally: self._tmp_output_file.close() cmd = '%s report -n -i %s' % (_NicePath( self._perfhost_binary), self._output_file) if self._is_android: device = self._browser_backend.device device.PullFile(self._device_output_file, self._output_file) required_libs = \ android_profiling_helper.GetRequiredLibrariesForPerfProfile( self._output_file) symfs_root = os.path.join(os.path.dirname(self._output_file), 'symfs') if not os.path.exists(symfs_root): os.makedirs(symfs_root) kallsyms = android_profiling_helper.CreateSymFs(device, symfs_root, required_libs, use_symlinks=True) cmd += ' --symfs %s --kallsyms %s' % (symfs_root, kallsyms) for lib in required_libs: lib = os.path.join(symfs_root, lib[1:]) if not os.path.exists(lib): continue objdump_path = android_profiling_helper.GetToolchainBinaryPath( lib, 'objdump') if objdump_path: cmd += ' --objdump %s' % _NicePath(objdump_path) break print 'To view the profile, run:' print ' ', cmd return self._output_file
def testGetRequiredLibrariesForPerfProfile(self): perf_output = os.path.join(util.GetUnittestDataDir(), 'sample_perf_report_output.txt') with open(perf_output) as f: perf_output = f.read() mock_popen = simple_mock.MockObject() mock_popen.ExpectCall('communicate').WillReturn([None, perf_output]) mock_subprocess = simple_mock.MockObject() mock_subprocess.ExpectCall('Popen').WithArgs( simple_mock.DONT_CARE).WillReturn(mock_popen) mock_subprocess.SetAttribute('PIPE', simple_mock.MockObject()) real_subprocess = android_profiling_helper.subprocess android_profiling_helper.subprocess = mock_subprocess try: libs = android_profiling_helper.GetRequiredLibrariesForPerfProfile( 'foo') self.assertEqual( libs, set([ '/data/app-lib/com.google.android.apps.chrome-2/libchrome.2016.0.so', '/system/lib/libart.so', '/system/lib/libc.so', '/system/lib/libm.so' ])) finally: android_profiling_helper.subprocess = real_subprocess
def PullTrace(self): symfs_dir = os.path.join(tempfile.gettempdir(), os.path.expandvars('$USER-perf-symfs')) if not os.path.exists(symfs_dir): os.makedirs(symfs_dir) required_libs = set() # Download the recorded perf profile. perf_profile = self._perf_instance.PullResult(symfs_dir) required_libs = \ android_profiling_helper.GetRequiredLibrariesForPerfProfile( perf_profile) if not required_libs: logging.warning( 'No libraries required by perf trace. Most likely there ' 'are no samples in the trace.') # Build a symfs with all the necessary libraries. kallsyms = android_profiling_helper.CreateSymFs(self._device, symfs_dir, required_libs, use_symlinks=False) perfhost_path = binary_manager.FetchPath( android_profiling_helper.GetPerfhostName(), 'x86_64', 'linux') ui.PrintMessage('\nNote: to view the profile in perf, run:') ui.PrintMessage(' ' + self._GetInteractivePerfCommand( perfhost_path, perf_profile, symfs_dir, required_libs, kallsyms)) # Convert the perf profile into JSON. perf_script_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'third_party', 'perf_to_tracing.py') json_file_name = os.path.basename(perf_profile) with open(os.devnull, 'w') as dev_null, \ open(json_file_name, 'w') as json_file: cmd = [ perfhost_path, 'script', '-s', perf_script_path, '-i', perf_profile, '--symfs', symfs_dir, '--kallsyms', kallsyms ] if subprocess.call(cmd, stdout=json_file, stderr=dev_null): logging.warning( 'Perf data to JSON conversion failed. The result will ' 'not contain any perf samples. You can still view the ' 'perf data manually as shown above.') return None return json_file_name