Scripts for getting data from app startup
Change-Id: I7433b2dbf6cc18625fa600df17bfeffe817952db
diff --git a/tools/startup/perfetto_utils.py b/tools/startup/perfetto_utils.py
new file mode 100644
index 0000000..d85f53e
--- /dev/null
+++ b/tools/startup/perfetto_utils.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+
+try:
+ from perfetto.trace_processor import TraceProcessor
+except ImportError:
+ sys.exit(
+ 'Unable to analyze perfetto trace without the perfetto library. '
+ 'Install instructions:\n'
+ ' sudo apt install python3-pip\n'
+ ' pip3 install perfetto')
+
+def ensure_record_android_trace(tmp_dir):
+ record_android_trace_path = os.path.join(tmp_dir, 'record_android_trace')
+ if not os.path.exists(record_android_trace_path):
+ cmd = [
+ 'curl',
+ '--output',
+ record_android_trace_path,
+ '--silent',
+ 'https://raw.githubusercontent.com/google/perfetto/master/tools/'
+ 'record_android_trace'
+ ]
+ subprocess.check_call(cmd)
+ assert os.path.exists(record_android_trace_path)
+ return record_android_trace_path
+
+def record_android_trace(out_dir, tmp_dir):
+ record_android_trace_path = ensure_record_android_trace(tmp_dir)
+ config_path = os.path.join(os.path.dirname(__file__), 'config.pbtx')
+ perfetto_trace_path = os.path.join(out_dir, 'trace.perfetto-trace')
+ cmd = [
+ sys.executable,
+ record_android_trace_path,
+ '--config',
+ config_path,
+ '--out',
+ perfetto_trace_path,
+ '--no-open']
+ perfetto_process = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ lines = []
+ for line in perfetto_process.stdout:
+ line = line.decode('utf-8')
+ lines.append(line)
+ if 'enabled ftrace' in line.strip():
+ return perfetto_process, perfetto_trace_path
+ raise ValueError(
+ 'Expected to find line containing: enabled ftrace, got: %s' % lines)
+
+def stop_record_android_trace(perfetto_process, out_dir):
+ if perfetto_process.poll() is not None:
+ raise ValueError('Expected perfetto process to be running')
+ # perfetto should terminate in at most 15 seconds,
+ perfetto_config_duration=15
+ stdout, stderr = perfetto_process.communicate(
+ timeout=perfetto_config_duration*2)
+ stdout = stdout.decode('utf-8')
+ stderr = stderr.decode('utf-8')
+ assert perfetto_process.returncode == 0
+ assert os.path.exists(os.path.join(out_dir, 'trace.perfetto-trace'))
+
+# https://perfetto.dev/docs/analysis/sql-tables
+def find_slices_by_name(slice_name, options, trace_processor):
+ return trace_processor.query(
+ 'SELECT slice.dur, slice.ts FROM slice'
+ ' INNER JOIN thread_track ON (slice.track_id = thread_track.id)'
+ ' INNER JOIN thread using (utid)'
+ ' INNER JOIN process using (upid)'
+ ' WHERE slice.name = "%s"'
+ ' AND process.name = "%s"'
+ ' ORDER BY slice.ts ASC'
+ % (slice_name, options.app_id))
+
+def find_unique_slice_by_name(slice_name, options, trace_processor):
+ query_it = find_slices_by_name(slice_name, options, trace_processor)
+ assert len(query_it) == 1
+ return next(query_it)
+
+def get_slice_end_since_start(slice, initial_slice):
+ return (slice.ts + slice.dur - initial_slice.ts) / 1000000