summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2018-04-11 17:50:56 -0700
committerYabin Cui <yabinc@google.com>2018-04-12 12:43:36 -0700
commitd5d9c4293b3d8b659905770bb9c501c6fa8e7c6f (patch)
treed3c232e5bf66c3ddda37327fb5692ee9b2d2ecfb
parenta6ee510913c53783875a5512ff0d00a26b31eaad (diff)
downloadextras-d5d9c4293b3d8b659905770bb9c501c6fa8e7c6f.tar.gz
simpleperf: add a python script to record without usb connection.
Also fix a bug handling SIGHUP when recording an app. Also add pylintrc and test. Bug: http://b/74198167 Test: run the script manually. Change-Id: I3f1f4a3a32364aace8f8887ea426f5a8764a55dd
-rw-r--r--simpleperf/environment.cpp6
-rw-r--r--simpleperf/scripts/pylintrc8
-rw-r--r--simpleperf/scripts/run_simpleperf_without_usb_connection.py94
-rw-r--r--simpleperf/scripts/test.py12
4 files changed, 118 insertions, 2 deletions
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index cf9167c2..9843ab0f 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -632,7 +632,11 @@ bool RunInAppContext(const std::string& app_package_name, const std::string& cmd
IOEventLoop loop;
bool need_to_kill_child = false;
- if (!loop.AddSignalEvents({SIGINT, SIGTERM, SIGHUP},
+ std::vector<int> stop_signals = {SIGINT, SIGTERM};
+ if (!SignalIsIgnored(SIGHUP)) {
+ stop_signals.push_back(SIGHUP);
+ }
+ if (!loop.AddSignalEvents(stop_signals,
[&]() { need_to_kill_child = true; return loop.ExitLoop(); })) {
return false;
}
diff --git a/simpleperf/scripts/pylintrc b/simpleperf/scripts/pylintrc
new file mode 100644
index 00000000..0a02cfcb
--- /dev/null
+++ b/simpleperf/scripts/pylintrc
@@ -0,0 +1,8 @@
+[MESSAGES CONTROL]
+# C0111 = Missing docstring
+# W0403 = Relative imports
+disable=C0111,W0403
+
+[BASIC]
+function-rgx=[a-z_][a-z0-9_]{2,50}$
+method-rgx=[a-z_][a-z0-9_]{2,50}$
diff --git a/simpleperf/scripts/run_simpleperf_without_usb_connection.py b/simpleperf/scripts/run_simpleperf_without_usb_connection.py
new file mode 100644
index 00000000..ef529e07
--- /dev/null
+++ b/simpleperf/scripts/run_simpleperf_without_usb_connection.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+ Support profiling without usb connection in below steps:
+ 1. With usb connection, start simpleperf recording.
+ 2. Unplug the usb cable and play the app you want to profile, while the process of
+ simpleperf keeps running and collecting samples.
+ 3. Replug the usb cable, stop simpleperf recording and pull recording file on host.
+
+ Note that recording is stopped once the app is killed. So if you restart the app
+ during profiling time, simpleperf only records the first running.
+"""
+
+from __future__ import print_function
+import argparse
+import subprocess
+import sys
+import time
+
+from utils import AdbHelper, get_target_binary_path, log_warning
+
+def start_recording(args):
+ adb = AdbHelper()
+ device_arch = adb.get_device_arch()
+ simpleperf_binary = get_target_binary_path(device_arch, 'simpleperf')
+ adb.check_run(['push', simpleperf_binary, '/data/local/tmp'])
+ adb.check_run(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf'])
+ adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/perf.data',
+ '/data/local/tmp/simpleperf_output'])
+ shell_cmd = 'cd /data/local/tmp && nohup ./simpleperf record ' + args.record_options
+ if args.app:
+ shell_cmd += ' --app ' + args.app
+ shell_cmd += ' >/data/local/tmp/simpleperf_output 2>&1'
+ print('shell_cmd: %s' % shell_cmd)
+ subproc = subprocess.Popen([adb.adb_path, 'shell', shell_cmd])
+ # Wait 2 seconds to see if the simpleperf command fails to start.
+ time.sleep(2)
+ if subproc.poll() is None:
+ print('Simpleperf recording has started. Please unplug the usb cable and run the app.')
+ print('After that, run `%s stop` to get recording result.' % sys.argv[0])
+ else:
+ adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output'])
+ sys.exit(subproc.returncode)
+
+def stop_recording(args):
+ adb = AdbHelper()
+ result = adb.run(['shell', 'pidof', 'simpleperf'])
+ if not result:
+ log_warning('No simpleperf process on device. The recording has ended.')
+ else:
+ adb.run(['shell', 'pkill', '-l', '2', 'simpleperf'])
+ print('Waiting for simpleperf process to finish...')
+ while adb.run(['shell', 'pidof', 'simpleperf']):
+ time.sleep(1)
+ adb.check_run(['pull', '/data/local/tmp/perf.data', args.perf_data_path])
+ adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output'])
+ print('The recording data has been collected in %s.' % args.perf_data_path)
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ subparsers = parser.add_subparsers()
+ start_parser = subparsers.add_parser('start', help='Start recording.')
+ start_parser.add_argument('-r', '--record_options',
+ default='-e task-clock:u -g',
+ help="""Set options for `simpleperf record` command.
+ Default is '-e task-clock:u -g --no-post-unwind.""")
+ start_parser.add_argument('-p', '--app', help="""Profile an Android app, given the package
+ name. Like -p com.example.android.myapp.""")
+ start_parser.set_defaults(func=start_recording)
+ stop_parser = subparsers.add_parser('stop', help='Stop recording.')
+ stop_parser.add_argument('-o', '--perf_data_path', default='perf.data', help="""The path to
+ store profiling data on host. Default is perf.data.""")
+ stop_parser.set_defaults(func=stop_recording)
+ args = parser.parse_args()
+ args.func(args)
+
+if __name__ == '__main__':
+ main()
diff --git a/simpleperf/scripts/test.py b/simpleperf/scripts/test.py
index cad5d703..c7215c30 100644
--- a/simpleperf/scripts/test.py
+++ b/simpleperf/scripts/test.py
@@ -454,6 +454,16 @@ class TestExamplePureJava(TestExampleBase):
def test_report_html(self):
self.common_test_report_html()
+ def test_run_simpleperf_without_usb_connection(self):
+ self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
+ self.run_cmd(['run_simpleperf_without_usb_connection.py', 'start', '-p',
+ self.package_name])
+ self.adb.check_run(['kill-server'])
+ time.sleep(3)
+ self.run_cmd(['run_simpleperf_without_usb_connection.py', 'stop'])
+ self.check_exist(file="perf.data")
+ self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+
class TestExamplePureJavaRoot(TestExampleBase):
@classmethod
@@ -1050,7 +1060,7 @@ class TestTools(unittest.TestCase):
readelf = ReadElf(None)
for dso_path in test_map:
dso_info = test_map[dso_path]
- path = 'testdata' + dso_path
+ path = 'testdata' + dso_path
self.assertEqual(dso_info['arch'], readelf.get_arch(path))
if 'build_id' in dso_info:
self.assertEqual(dso_info['build_id'], readelf.get_build_id(path))