Add query function to Python API for trace processor.
This CL does the following:
1. Add basic query function to call http.py functions and pass along response
2. Implement QueryResultIterator class to represent the results of a user input query
3. Add metric function to return desired metrics if not erroneous input
Change-Id: I09769acfb407cd81ccf1d540908d20ccd74f4ca8
diff --git a/src/trace_processor/python/example.py b/src/trace_processor/python/example.py
index 162b337..59dc9f2 100644
--- a/src/trace_processor/python/example.py
+++ b/src/trace_processor/python/example.py
@@ -15,7 +15,7 @@
import argparse
-from trace_processor.http import TraceProcessorHttp
+from trace_processor.api import TraceProcessor
def main():
@@ -34,10 +34,11 @@
# TODO(@aninditaghosh): Load trace into trace_processor_shell
# Call functions on the loaded trace
- tp = TraceProcessorHttp(args.address)
- tp.notify_eof()
- print(tp.execute_query('select name from slice limit 10'))
- print(tp.status())
+ 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'])
if __name__ == "__main__":
diff --git a/src/trace_processor/python/trace_processor/api.py b/src/trace_processor/python/trace_processor/api.py
new file mode 100644
index 0000000..f980e2f
--- /dev/null
+++ b/src/trace_processor/python/trace_processor/api.py
@@ -0,0 +1,87 @@
+# 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 .http import TraceProcessorHttp
+
+
+class TraceProcessor:
+
+ # Values of these constants correspond to the QueryResponse message at
+ # protos/perfetto/trace_processor/trace_processor.proto
+ # Values 0 and 1 correspond to CELL_INVALID and CELL_NULL respectively,
+ # which are both represented as None in this class's response
+ QUERY_CELL_VARINT_FIELD_ID = 2
+ QUERY_CELL_FLOAT64_FIELD_ID = 3
+ QUERY_CELL_STRING_FIELD_ID = 4
+ QUERY_CELL_BLOB_FIELD_ID = 5
+
+ # This is the class returned to the user and contains one row of the
+ # resultant query. Each column name is stored as an attribute of this
+ # class, with the value corresponding to the column name and row in
+ # the query results table.
+ class Row:
+ pass
+
+ class QueryResultIterator:
+
+ def __init__(self, column_names, batches):
+ self.__cells = batches[0].cells
+ self.__varint_cells = batches[0].varint_cells
+ self.__float64_cells = batches[0].float64_cells
+ self.__blob_cells = batches[0].blob_cells
+ # TODO(aninditaghosh): Revisit string cells for larger traces
+ self.__string_cells = batches[0].string_cells.split('\0')
+ self.__column_names = column_names
+
+ def get_cell_list(self, proto_index):
+ if proto_index == TraceProcessor.QUERY_CELL_VARINT_FIELD_ID:
+ return self.__varint_cells
+ elif proto_index == TraceProcessor.QUERY_CELL_FLOAT64_FIELD_ID:
+ return self.__float64_cells
+ elif proto_index == TraceProcessor.QUERY_CELL_STRING_FIELD_ID:
+ return self.__string_cells
+ elif proto_index == TraceProcessor.QUERY_CELL_BLOB_FIELD_ID:
+ return self.__blob_cells
+ else:
+ return None
+
+ def __iter__(self):
+ self.__next_index = 0
+ return self
+
+ def __next__(self):
+ if self.__next_index >= len(self.__cells):
+ raise StopIteration
+ row = TraceProcessor.Row()
+ for num, column_name in enumerate(self.__column_names):
+ cell_list = self.get_cell_list(self.__cells[self.__next_index + num])
+ if cell_list is not None:
+ val = cell_list.pop(0)
+ setattr(row, column_name, val or None)
+ self.__next_index = self.__next_index + len(self.__column_names)
+ return row
+
+ def __init__(self, uri):
+ self.http = TraceProcessorHttp(uri)
+
+ def query(self, sql):
+ response = self.http.execute_query(sql)
+ return TraceProcessor.QueryResultIterator(response.column_names,
+ response.batch)
+
+ def metric(self, metrics):
+ response = self.http.compute_metric(metrics)
+ if response.error:
+ raise Exception(response.error)
+ return response.metrics