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 testCreateSymFs(self): # pylint: disable=protected-access browser_pid = self._browser._browser_backend.pid pids = ([browser_pid] + self._browser._platform_backend.GetChildPids(browser_pid)) libs = _GetLibrariesMappedIntoProcesses(self._device, pids) assert libs symfs_dir = tempfile.mkdtemp() try: kallsyms = android_profiling_helper.CreateSymFs( self._device, symfs_dir, libs) # Check that we have kernel symbols. assert os.path.exists(kallsyms) is_unstripped = re.compile(r'^/data/app(-lib)?/.*\.so$') has_unstripped = False # Check that all requested libraries are present. for lib in libs: has_unstripped = has_unstripped or is_unstripped.match(lib) assert os.path.exists(os.path.join(symfs_dir, lib[1:])), \ '%s not found in symfs' % lib # Make sure we found at least one unstripped library. assert has_unstripped finally: shutil.rmtree(symfs_dir)
def CollectProfile(self): if 'renderer' in self._output_file: try: self._platform_backend.GetCommandLine(self._pid) except exceptions.ProcessGoneException: logging.warning('Renderer was swapped out during profiling. ' 'To collect a full profile rerun with ' '"--extra-browser-args=--single-process"') subprocess.call( ['amplxe-cl', '-command', 'stop', '-r', self._output_file]) exit_code = self._proc.wait() try: # 1: amplxe: Error: Cannot find a running process with the specified ID. # Provide a valid PID. if exit_code not in (0, 1): raise Exception( 'amplxe-cl failed with exit code %d. Output:\n%s' % (exit_code, self._GetStdOut())) finally: self._tmp_output_file.close() if exit_code: # The renderer process was swapped out. Now that we made sure VTune has # stopped, return without further processing the invalid profile. return self._output_file if self._is_android: required_libs = \ android_profiling_helper.GetRequiredLibrariesForVTuneProfile( self._output_file) device = self._browser_backend.device symfs_root = os.path.join(os.path.dirname(self._output_file), 'symfs') if not os.path.exists(symfs_root): os.makedirs(symfs_root) android_profiling_helper.CreateSymFs(device, symfs_root, required_libs, use_symlinks=True) logging.info('Resolving symbols in profile.') subprocess.call([ 'amplxe-cl', '-finalize', '-r', self._output_file, '-search-dir', symfs_root ]) print 'To view the profile, run:' print ' amplxe-gui %s' % self._output_file return self._output_file
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