1# Copyright 2016-2017 ARM Limited 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16from trappy.ftrace import GenericFTrace 17import re 18 19SYSTRACE_EVENT = re.compile( 20 r'^(?P<event>[A-Z])(\|(?P<pid>\d+)\|(?P<func>[^|]*)(\|(?P<data>.*))?)?') 21 22class drop_before_trace(object): 23 """Object that, when called, returns True if the line is not part of 24the trace 25 26 We have to first look for the "<!-- BEGIN TRACE -->" and then skip 27 the headers that start with # 28 29 """ 30 def __init__(self, tracer): 31 self.before_begin_trace = True 32 self.before_actual_trace = True 33 self.tracer = tracer 34 35 def __call__(self, line): 36 if self.before_begin_trace: 37 if line.startswith("<!-- BEGIN TRACE -->") or \ 38 line.startswith("<title>Android System Trace</title>"): 39 self.before_begin_trace = False 40 elif self.before_actual_trace: 41 if line.startswith(' <script class="trace-data"') or \ 42 line.startswith(" var linuxPerfData"): 43 self.before_actual_trace = False 44 45 if not self.before_actual_trace: 46 base_call = super(SysTrace, self.tracer).trace_hasnt_started() 47 return base_call(line) 48 else: 49 return True 50 51class SysTrace(GenericFTrace): 52 """A wrapper that parses all events of a SysTrace run 53 54 It receives the same parameters as :mod:`trappy.ftrace.FTrace`. 55 56 """ 57 58 def __init__(self, path=".", name="", normalize_time=True, scope="all", 59 events=[], window=(0, None), abs_window=(0, None)): 60 61 self.trace_path = path 62 63 super(SysTrace, self).__init__(name, normalize_time, scope, events, 64 window, abs_window) 65 66 self._do_parse() 67 try: 68 self._cpus = 1 + self.sched_switch.data_frame["__cpu"].max() 69 except AttributeError: 70 pass 71 72 def trace_hasnt_started(self): 73 return drop_before_trace(self) 74 75 def trace_hasnt_finished(self): 76 """Return a function that returns True while the current line is still part of the trace 77 78 In Systrace, the first line that is not part of the trace is 79 </script>. There's a further "<!-- END TRACE -->" but there's 80 not point scanning for it, we should stop parsing as soon as 81 we see the </script> 82 83 """ 84 return lambda x: not x.endswith("</script>\n") 85 86 def generate_data_dict(self, data_str): 87 """ Custom parsing for systrace's userspace events """ 88 data_dict = None 89 90 match = SYSTRACE_EVENT.match(data_str) 91 if match: 92 data_dict = { 93 'event': match.group('event'), 94 'pid' : int(match.group('pid')) if match.group('pid') else None, 95 'func' : match.group('func' ), 96 'data' : match.group('data' ) 97 } 98 99 return data_dict 100