| # 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. |
| """Utility to extract parts of a trace based on a SQL expression""" |
| import sys |
| import logging |
| |
| from .model import TraceAnalysisSession, FileTraceContext |
| from .sql import identifier_quote |
| from ._native import dump_events_to_fd |
| from .util import ureg |
| |
| log = logging.getLogger(__name__) |
| |
| def run_subset(*, |
| trace_file_name, |
| filter_expression, |
| absolute_time=False, |
| out_file=None): |
| """Run the subset command-line utility""" |
| trace_session = TraceAnalysisSession() |
| time_basis_override = 0 if absolute_time else None |
| trace_session.mount_trace(["trace"], |
| FileTraceContext( |
| trace_file_name, |
| time_basis_override=time_basis_override), |
| temp_hack_lenient_metadata=True) |
| q = "SELECT type FROM trace.found_event_types" |
| found_event_types = trace_session.sql_query1(q).tolist() |
| if not found_event_types: |
| log.warning("no events found in trace?!") |
| return |
| |
| def _query_for_event_type(event_type): |
| return "SELECT _pos FROM trace.raw_events.{} WHERE ({})".format( |
| identifier_quote(event_type), filter_expression) |
| queries = [_query_for_event_type(event_type) |
| for event_type in found_event_types] |
| |
| valid_queries = [] |
| for event_type, query in zip(found_event_types, queries): |
| try: |
| trace_session.parse_sql_query(query) |
| except Exception as ex: |
| log.warning("query %r does not work for event type %r: " |
| "filtering out this event type", query, event_type) |
| log.warning("query error was %r", ex) |
| continue |
| valid_queries.append(query) |
| if not valid_queries: |
| log.warning("no events could, syntactically, match filter!") |
| return |
| q = " UNION ALL ".join( |
| "({})".format(query) for query in valid_queries) + " ORDER BY _pos" |
| |
| cursor = trace_session.sql_query(q, |
| output_format="rows", |
| want_schema=True) |
| trace_info = trace_session.get_mounted_trace(["trace"]) |
| nr_cpus = trace_info.metadata.get("nr_cpus") |
| out_file = out_file or sys.stdout |
| if nr_cpus is not None: |
| out_file.write("cpus={}\n".format(nr_cpus)) |
| out_file.flush() |
| mapping = trace_info.mapped_trace.mapping |
| for row, _is_eof in cursor: |
| pos_array, pos_schema = row["_pos"] |
| assert pos_schema.unit == ureg().bytes |
| dump_events_to_fd(mapping, pos_array, out_file.fileno()) |
| out_file.flush() |