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