Load in trace_processor shell given file path to trace
Change-Id: Iba677ca156c81510c1285eca0c8f2215965802de
diff --git a/src/trace_processor/python/example.py b/src/trace_processor/python/example.py
index 59dc9f2..fd27903 100644
--- a/src/trace_processor/python/example.py
+++ b/src/trace_processor/python/example.py
@@ -24,21 +24,27 @@
parser.add_argument(
"-a",
"--address",
- help="Address at which trace_processor is being run, e.g. 127.0.0.1:9001",
- required=True,
+ help="Address at which trace_processor is being run, e.g. localhost:9001",
type=str)
- parser.add_argument(
- "-f", "--file", help="Absolute path to trace", required=True, type=str)
+ parser.add_argument("-f", "--file", help="Absolute path to trace", type=str)
args = parser.parse_args()
- # TODO(@aninditaghosh): Load trace into trace_processor_shell
+ # Pass arguments into api to construct the trace processor and load the trace
+ if args.address == None and args.file == None:
+ raise Exception("You must specify an address or a file path to trace")
+ elif args.address == None:
+ tp = TraceProcessor(file_path=args.file)
+ elif args.file == None:
+ tp = TraceProcessor(uri=args.address)
+ else:
+ tp = TraceProcessor(uri=args.address, file_path=args.file)
# Call functions on the loaded trace
- tp = TraceProcessor(args.address)
res_it = tp.query('select * from slice limit 10')
for row in res_it:
print(row.name)
am_metrics = tp.metric(['android_mem'])
+ tp.close()
if __name__ == "__main__":
diff --git a/src/trace_processor/python/trace_processor/api.py b/src/trace_processor/python/trace_processor/api.py
index f980e2f..c559f92 100644
--- a/src/trace_processor/python/trace_processor/api.py
+++ b/src/trace_processor/python/trace_processor/api.py
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from urllib.parse import urlparse
+
from .http import TraceProcessorHttp
+from .parse import parse_file
+from .shell import load_shell
class TraceProcessor:
@@ -36,6 +40,7 @@
class QueryResultIterator:
def __init__(self, column_names, batches):
+ # TODO(@aninditaghosh): Revisit to handle multiple batches
self.__cells = batches[0].cells
self.__varint_cells = batches[0].varint_cells
self.__float64_cells = batches[0].float64_cells
@@ -72,8 +77,19 @@
self.__next_index = self.__next_index + len(self.__column_names)
return row
- def __init__(self, uri):
- self.http = TraceProcessorHttp(uri)
+ def __init__(self, uri=None, file_path=None):
+ # Load trace_processor_shell or access via given address
+ if uri:
+ p = urlparse(uri)
+ tp = TraceProcessorHttp(p.netloc if p.netloc else p.path)
+ else:
+ url, self.subprocess = load_shell()
+ tp = TraceProcessorHttp(url)
+ self.http = tp
+
+ # Parse trace by its file_path into the loaded instance of trace_processor
+ if file_path:
+ parse_file(self.http, file_path)
def query(self, sql):
response = self.http.execute_query(sql)
@@ -85,3 +101,9 @@
if response.error:
raise Exception(response.error)
return response.metrics
+
+ # TODO(@aninditaghosh): Investigate context managers for
+ # cleaner usage
+ def close(self):
+ if hasattr(self, 'subprocess'):
+ self.subprocess.kill()
diff --git a/src/trace_processor/python/trace_processor/parse.py b/src/trace_processor/python/trace_processor/parse.py
new file mode 100644
index 0000000..703633f
--- /dev/null
+++ b/src/trace_processor/python/trace_processor/parse.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 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.
+
+import os
+
+# Limit parsing file to 32MB to maintain parity with the UI
+MAX_BYTES_LOADED = 32 * 1024 * 1024
+
+
+def parse_file(tp_http, file_path):
+ try:
+ from .parse_vendor import parse_file_vendor
+ return parse_file_vendor(tp_http, file_path)
+ except ModuleNotFoundError:
+ with open(file_path, 'rb') as f:
+ f_size = os.path.getsize(file_path)
+ bytes_read = 0
+ while (bytes_read < f_size):
+ chunk = f.read(MAX_BYTES_LOADED)
+ tp_http.parse(chunk)
+ bytes_read += len(chunk)
+ tp_http.notify_eof()
+ return tp_http
diff --git a/src/trace_processor/python/trace_processor/shell.py b/src/trace_processor/python/trace_processor/shell.py
new file mode 100644
index 0000000..c77a95d
--- /dev/null
+++ b/src/trace_processor/python/trace_processor/shell.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 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.
+
+from urllib import request, error
+import subprocess
+import tempfile
+import time
+
+# URL to download script to run trace_processor
+SHELL_URL = 'http://get.perfetto.dev/trace_processor'
+
+
+def load_shell():
+ try:
+ from .shell_vendor import load_shell_vendor
+ shell_path = load_shell_vendor()
+ except ModuleNotFoundError:
+ # TODO(@aninditaghosh): Try to use preexisting binary before
+ # attempting to download trace_processor
+ with tempfile.NamedTemporaryFile(delete=False) as file:
+ req = request.Request(SHELL_URL)
+ with request.urlopen(req) as req:
+ file.write(req.read())
+ shell_path = file.name
+ subprocess.check_output(['chmod', '+x', shell_path])
+
+ p = subprocess.Popen([shell_path, '-D'], stdout=subprocess.DEVNULL)
+
+ while True:
+ try:
+ req = request.urlretrieve('http://localhost:9001/status')
+ time.sleep(1)
+ break
+ except error.URLError:
+ pass
+ return 'localhost:9001', p