Beispiel #1
0
    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
Beispiel #3
0
    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