Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / profile_chrome / third_party / perf_to_tracing.py
1 # Script for converting perf script events into tracing JSON.
2 #
3 # Generated by perf script -g python
4 # Licensed under the terms of the GNU GPL License version 2
5
6 import json
7 import os
8 import sys
9
10 from collections import deque
11
12
13 # Categorize DSOs by component.
14 dso_to_comp = {
15     'libdvm.so': 'Java',
16     'libart.so': 'Java',
17     'libjavacore.so': 'Java',
18     'libandroid_runtime.so': 'Android',
19     'libgui.so': 'Android',
20     'libui.so': 'Android',
21     'libbinder.so': 'Android',
22     'libmemalloc.so': 'Android',
23     'libcrypto.so': 'Android',
24     'libcutils.so':'Android',
25     'libutils.so': 'Android',
26     '[kernel.kallsyms]': 'Kernel',
27     'libc.so': 'Standard Lib',
28     'libstdc++.so': 'Standard Lib',
29     'libm.so':'Standard Lib',
30     'libGLESv2_adreno.so': 'GPU Driver',
31     'libGLESv2_adreno200.so': 'GPU Driver',
32     'libq3dtools_adreno200.so': 'GPU Driver',
33     'libEGL_adreno.so': 'GPU Driver',
34     'libEGL_adreno200.so': 'GPU Driver',
35     'libEGL.so': 'GPU Driver',
36     'libgsl.so': 'GPU Driver',
37     'libGLESv2.so': 'GPU Driver',
38     'libsc-a3xx.so': 'GPU Driver',
39     'libadreno_utils.so': 'GPU Driver',
40     'eglsubAndroid.so': 'GPU Driver',
41     'gralloc.msm8960.so': 'GPU Driver',
42     'libadreno_utils': 'GPU Driver',
43     'libGLES_mali.so': 'GPU Driver',
44     'libchromeview.so': 'Chrome',
45     '[unknown]': '<unknown>',
46     '[UNKNOWN]': '<unknown>',
47 }
48
49
50 def FilterSymbolModule(module):
51   m = dso_to_comp.get(module, None)
52   if m:
53     return m
54   if module.find('libchrome.') == 0:
55     return 'Chrome'
56   if module.find('dalvik') >= 0 or module.find('@') >= 0:
57     return 'Java'
58   return module
59
60
61 def FilterSymbolName(module, orign_module, name):
62   if module == 'Java':
63     return name
64   elif module == 'GPU Driver':
65     return name
66   if name == '':
67     return orign_module + ':unknown'
68   if name[0].isdigit() or name == '(nil)':
69     return orign_module + ':unknown'
70   return name
71
72
73 class StackFrameNode:
74   def __init__(self, stack_id, name, category):
75     self.stack_id = stack_id
76     self.parent_id = 0
77     self.children = {}
78     self.category = category
79     self.name = name
80     self.samples = []
81     self.total_weight = 0.0
82     self.have_total_weight = False
83     self.parent = None
84
85   def ToDict(self, out_dict):
86     if self.stack_id:
87       node_dict = {}
88       node_dict['name'] = self.name
89       node_dict['category'] = self.category
90       if self.parent_id:
91         node_dict['parent'] = self.parent_id
92
93       out_dict[self.stack_id] = node_dict
94
95     for child in self.children.values():
96       child.ToDict(out_dict)
97     return out_dict
98
99   def GetTotalWeight(self):
100     if self.have_total_weight:
101       return self.total_weight
102     else:
103       # Sum up self samples weight, and children's total weights.
104       for s in self.samples:
105         self.total_weight += s.weight
106       for c in self.children.values():
107         self.total_weight += c.GetTotalWeight()
108       self.have_total_weight = True
109       return self.total_weight
110
111
112 class PerfSample:
113   def __init__(self, stack_id, ts, cpu, tid, weight, samp_type, comm):
114     self.stack_id = stack_id
115     self.ts = ts
116     self.cpu = cpu
117     self.tid = tid
118     self.weight = weight
119     self.type = samp_type
120     self.comm = comm
121
122   def ToDict(self):
123     ret = {}
124     ret['ts'] = self.ts / 1000.0  # Timestamp in microseconds
125     ret['tid'] = self.tid  # Thread id
126     ret['cpu'] = self.cpu  # Sampled CPU
127     ret['weight'] = self.weight  # Sample weight
128     ret['name'] = self.type  # Sample type
129     ret['comm'] = self.comm  # Sample type
130     assert self.stack_id != 0
131     if self.stack_id:
132       ret['sf'] = self.stack_id  # Stack frame id
133     return ret
134
135
136 samples = []
137 root_chain = StackFrameNode(0, 'root', '[unknown]')
138 next_stack_id = 1
139 tot_period = 0
140 saved_period = 0
141
142
143 def process_event(param_dict):
144   global next_stack_id
145   global saved_period
146   global tot_period
147
148   samp_comm = param_dict['comm']
149   samp_tid = param_dict['tid']
150   samp_cpu = param_dict['cpu']
151   samp_ts = param_dict['time']
152   samp_period = param_dict['period']
153   samp_type = param_dict['ev_name']
154   tot_period += samp_period
155
156   # Parse call chain.
157   seen_syms = set()
158   chain = deque()
159   for cs in param_dict['cs']:
160     cs_name = cs[0]
161     cs_dso = os.path.basename(cs[1])
162     cs_category = FilterSymbolModule(cs_dso)
163     cs_name = FilterSymbolName(cs_category, cs_dso, cs_name)
164
165     if cs_category != '<unknown>' or len(chain) == 0:
166       sym = (cs_name, cs_category)
167       if sym in seen_syms:
168         while chain[0] != sym:
169           seen_syms.remove(chain[0])
170           chain.popleft()
171       else:
172         seen_syms.add(sym)
173         chain.appendleft(sym)
174
175       # Discard garbage stacktrace before __pthread_start()
176       if cs_name == '__pthread_start(void*)':
177         break
178
179   # Done reading call chain.  Add to stack frame tree.
180   stack_frame = root_chain
181   for call in chain:
182     if call in stack_frame.children:
183       stack_frame = stack_frame.children[call]
184     else:
185       new_node = StackFrameNode(next_stack_id, call[0], call[1])
186       next_stack_id += 1
187       new_node.parent_id = stack_frame.stack_id
188       stack_frame.children[call] = new_node
189       stack_frame = new_node
190
191   # Save sample.
192   sample = PerfSample(stack_frame.stack_id,
193                   samp_ts,
194                   samp_cpu,
195                   samp_tid,
196                   samp_period,
197                   samp_type,
198                   samp_comm)
199   samples.append(sample)
200   stack_frame.samples.append(sample)
201   saved_period += samp_period
202
203
204 def trace_begin():
205   pass
206
207
208 def trace_end():
209   # Return siblings of a call tree node.
210   def GetNodeSiblings(node):
211     if not node:
212       return []
213     if not node.parent:
214       return []
215     return node.parent.children.values()
216
217   # Try to reduce misplaced stack leaves by moving them up into sibling nodes.
218   def FixCallTree(node, parent):
219     # Get siblings of node's parent.
220     node.parent = parent
221     parent_siblings = GetNodeSiblings(parent)
222
223     # If parent's sibling has same node name, has no children and small weight,
224     # transplant sibling's samples into the current node.
225     for sibling in parent_siblings:
226       if sibling.name == node.name and \
227           len(sibling.children) == 0 and \
228           sibling.GetTotalWeight() <= node.GetTotalWeight() * 0.15:
229
230         # Transplant samples from sibling to current node.
231         for samp in sibling.samples:
232           samp.stack_id = node.stack_id
233           node.samples.append(samp)
234         sibling.samples = []
235         break
236
237     # Recurse child nodes.
238     for c in node.children.values():
239       FixCallTree(c, node)
240
241   FixCallTree(root_chain, None)
242
243   trace_dict = {}
244   trace_dict['samples'] = [s.ToDict() for s in samples]
245   trace_dict['stackFrames'] = root_chain.ToDict({})
246   trace_dict['traceEvents'] = []
247
248   json.dump(trace_dict, sys.stdout, indent=1)