Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file |
| 3 | # for details. All rights reserved. Use of this source code is governed by a |
| 4 | # BSD-style license that can be found in the LICENSE file. |
| 5 | |
| 6 | import os |
| 7 | import subprocess |
| 8 | import sys |
| 9 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 10 | |
Christoffer Quist Adamsen | 2d97341 | 2023-08-18 14:57:10 +0200 | [diff] [blame] | 11 | def get_trace_processor(): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 12 | try: |
| 13 | from perfetto.trace_processor import TraceProcessor |
| 14 | except ImportError: |
| 15 | sys.exit( |
| 16 | 'Unable to analyze perfetto trace without the perfetto library. ' |
| 17 | 'Install instructions:\n' |
| 18 | ' sudo apt install python3-pip\n' |
| 19 | ' pip3 install perfetto') |
| 20 | return TraceProcessor |
| 21 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 22 | |
| 23 | def ensure_record_android_trace(tmp_dir): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 24 | record_android_trace_path = os.path.join(tmp_dir, 'record_android_trace') |
| 25 | if not os.path.exists(record_android_trace_path): |
| 26 | cmd = [ |
| 27 | 'curl', '--output', record_android_trace_path, '--silent', |
| 28 | 'https://raw.githubusercontent.com/google/perfetto/master/tools/' |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 29 | 'record_android_trace' |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 30 | ] |
| 31 | subprocess.check_call(cmd) |
| 32 | assert os.path.exists(record_android_trace_path) |
| 33 | return record_android_trace_path |
| 34 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 35 | |
Christoffer Quist Adamsen | 3f7e428 | 2022-04-21 13:12:31 +0200 | [diff] [blame] | 36 | def record_android_trace(out_dir, tmp_dir, device_id=None): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 37 | record_android_trace_path = ensure_record_android_trace(tmp_dir) |
| 38 | config_path = os.path.join(os.path.dirname(__file__), 'config.pbtx') |
| 39 | perfetto_trace_path = os.path.join(out_dir, 'trace.perfetto-trace') |
| 40 | cmd = [ |
| 41 | sys.executable, record_android_trace_path, '--config', config_path, |
| 42 | '--out', perfetto_trace_path, '--no-open' |
| 43 | ] |
| 44 | if device_id is not None: |
| 45 | cmd.extend(['--serial', device_id]) |
| 46 | perfetto_process = subprocess.Popen(cmd, |
| 47 | stdout=subprocess.PIPE, |
| 48 | stderr=subprocess.PIPE) |
| 49 | lines = [] |
| 50 | for line in perfetto_process.stdout: |
| 51 | line = line.decode('utf-8') |
| 52 | lines.append(line) |
| 53 | if 'enabled ftrace' in line.strip(): |
| 54 | return perfetto_process, perfetto_trace_path |
| 55 | raise ValueError( |
| 56 | 'Expected to find line containing: enabled ftrace, got: %s' % lines) |
| 57 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 58 | |
| 59 | def stop_record_android_trace(perfetto_process, out_dir): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 60 | if perfetto_process.poll() is not None: |
| 61 | raise ValueError('Expected perfetto process to be running') |
| 62 | # perfetto should terminate in at most 15 seconds, |
| 63 | perfetto_config_duration = 15 |
| 64 | stdout, stderr = perfetto_process.communicate( |
| 65 | timeout=perfetto_config_duration * 2) |
| 66 | stdout = stdout.decode('utf-8') |
| 67 | stderr = stderr.decode('utf-8') |
| 68 | assert perfetto_process.returncode == 0 |
| 69 | assert os.path.exists(os.path.join(out_dir, 'trace.perfetto-trace')) |
| 70 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 71 | |
| 72 | # https://perfetto.dev/docs/analysis/sql-tables |
| 73 | def find_slices_by_name(slice_name, options, trace_processor): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 74 | return trace_processor.query( |
| 75 | 'SELECT slice.dur, slice.ts FROM slice' |
| 76 | ' INNER JOIN thread_track ON (slice.track_id = thread_track.id)' |
| 77 | ' INNER JOIN thread using (utid)' |
| 78 | ' INNER JOIN process using (upid)' |
| 79 | ' WHERE slice.name = "%s"' |
| 80 | ' AND process.name = "%s"' |
| 81 | ' ORDER BY slice.ts ASC' % (slice_name, options.app_id)) |
| 82 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 83 | |
| 84 | def find_unique_slice_by_name(slice_name, options, trace_processor): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 85 | query_it = find_slices_by_name(slice_name, options, trace_processor) |
| 86 | assert len(query_it) == 1 |
| 87 | return next(query_it) |
| 88 | |
Christoffer Quist Adamsen | fad33a0 | 2022-03-14 14:45:09 +0100 | [diff] [blame] | 89 | |
| 90 | def get_slice_end_since_start(slice, initial_slice): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 91 | return (slice.ts + slice.dur - initial_slice.ts) / 1000000 |