1e81fdcb135d0325e3bc22fae0583555d20aae280Brendan Jackman#    Copyright 2016-2017 ARM Limited
246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino#
346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# Licensed under the Apache License, Version 2.0 (the "License");
446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# you may not use this file except in compliance with the License.
546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# You may obtain a copy of the License at
646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino#
746458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino#     http://www.apache.org/licenses/LICENSE-2.0
846458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino#
946458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# Unless required by applicable law or agreed to in writing, software
1046458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# distributed under the License is distributed on an "AS IS" BASIS,
1146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# See the License for the specific language governing permissions and
1346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino# limitations under the License.
1446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino#
1546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
1646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merinofrom trappy.ftrace import GenericFTrace
172e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandesimport re
182e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes
192e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel FernandesSYSTRACE_EVENT = re.compile(
20a38f1d59a8927bf305a106478c2cf1cadbd564beJoel Fernandes    r'^(?P<event>[A-Z])(\|(?P<pid>\d+)\|(?P<func>[^|]*)(\|(?P<data>.*))?)?')
2146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
2246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merinoclass drop_before_trace(object):
2346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    """Object that, when called, returns True if the line is not part of
2446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merinothe trace
2546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
2646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    We have to first look for the "<!-- BEGIN TRACE -->" and then skip
2746458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    the headers that start with #
2846458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
2946458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    """
30ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes    def __init__(self, tracer):
3146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        self.before_begin_trace = True
3246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        self.before_actual_trace = True
33ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes        self.tracer = tracer
3446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
3546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    def __call__(self, line):
3646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        if self.before_begin_trace:
37459dadaf28d43f4c06c0587ff3193732b5bca1f5Leo Yan            if line.startswith("<!-- BEGIN TRACE -->") or \
38459dadaf28d43f4c06c0587ff3193732b5bca1f5Leo Yan               line.startswith("<title>Android System Trace</title>"):
3946458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino                self.before_begin_trace = False
40ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes        elif self.before_actual_trace:
41459dadaf28d43f4c06c0587ff3193732b5bca1f5Leo Yan            if line.startswith('  <script class="trace-data"') or \
42459dadaf28d43f4c06c0587ff3193732b5bca1f5Leo Yan               line.startswith("  var linuxPerfData"):
43ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes                self.before_actual_trace = False
4446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
45ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes        if not self.before_actual_trace:
46ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes            base_call = super(SysTrace, self.tracer).trace_hasnt_started()
47ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes            return base_call(line)
48ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes        else:
49ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes            return True
5046458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
5146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merinoclass SysTrace(GenericFTrace):
5246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    """A wrapper that parses all events of a SysTrace run
5346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
5446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    It receives the same parameters as :mod:`trappy.ftrace.FTrace`.
5546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
5646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    """
5746458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
5846458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    def __init__(self, path=".", name="", normalize_time=True, scope="all",
5946458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino                 events=[], window=(0, None), abs_window=(0, None)):
6046458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
6146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        self.trace_path = path
6246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
6346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        super(SysTrace, self).__init__(name, normalize_time, scope, events,
6446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino                                       window, abs_window)
6546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
66b01c848f3928dfcdf2f3d7dae1343bbe677847efChris Redpath        self._do_parse()
67cdae1b21d707108002b691c9bbc6da8b4d806668Patrick Bellasi        try:
68cdae1b21d707108002b691c9bbc6da8b4d806668Patrick Bellasi            self._cpus = 1 + self.sched_switch.data_frame["__cpu"].max()
69cdae1b21d707108002b691c9bbc6da8b4d806668Patrick Bellasi        except AttributeError:
70cdae1b21d707108002b691c9bbc6da8b4d806668Patrick Bellasi            pass
71cdae1b21d707108002b691c9bbc6da8b4d806668Patrick Bellasi
7246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    def trace_hasnt_started(self):
73ee6fb473add14fb3e2947bb57c7e1fc86c172a46Joel Fernandes        return drop_before_trace(self)
7446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
7546458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino    def trace_hasnt_finished(self):
7646458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        """Return a function that returns True while the current line is still part of the trace
7746458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
7846458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        In Systrace, the first line that is not part of the trace is
7946458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        </script>.  There's a further "<!-- END TRACE -->" but there's
8046458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        not point scanning for it, we should stop parsing as soon as
8146458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        we see the </script>
8246458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino
8346458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        """
8446458d66cd5118b6d9cac7cb455f8dae1286b9b2Javi Merino        return lambda x: not x.endswith("</script>\n")
852e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes
862e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes    def generate_data_dict(self, data_str):
872e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes        """ Custom parsing for systrace's userspace events """
882e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes        data_dict = None
892e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes
902e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes        match = SYSTRACE_EVENT.match(data_str)
912e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes        if match:
92609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes            data_dict = {
93609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes                          'event': match.group('event'),
94609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes                          'pid'  : int(match.group('pid')) if match.group('pid') else None,
95609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes                          'func' : match.group('func' ),
96609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes                          'data' : match.group('data' )
97609a57afbb408c756357aa95f36713fa77be1865Joel Fernandes                        }
982e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes
992e58198d1ea27e93a0e8c622d1ecc13be06f645fJoel Fernandes        return data_dict
100