1 # Script for converting perf script events into tracing JSON.
3 # Generated by perf script -g python
4 # Licensed under the terms of the GNU GPL License version 2
10 from collections
import deque
13 # Categorize DSOs by component.
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>',
50 def FilterSymbolModule(module
):
51 m
= dso_to_comp
.get(module
, None)
54 if module
.find('libchrome.') == 0:
56 if module
.find('dalvik') >= 0 or module
.find('@') >= 0:
61 def FilterSymbolName(module
, orign_module
, name
):
64 elif module
== 'GPU Driver':
67 return orign_module
+ ':unknown'
68 if name
[0].isdigit() or name
== '(nil)':
69 return orign_module
+ ':unknown'
74 def __init__(self
, stack_id
, name
, category
):
75 self
.stack_id
= stack_id
78 self
.category
= category
81 self
.total_weight
= 0.0
82 self
.have_total_weight
= False
85 def ToDict(self
, out_dict
):
88 node_dict
['name'] = self
.name
89 node_dict
['category'] = self
.category
91 node_dict
['parent'] = self
.parent_id
93 out_dict
[self
.stack_id
] = node_dict
95 for child
in self
.children
.values():
96 child
.ToDict(out_dict
)
99 def GetTotalWeight(self
):
100 if self
.have_total_weight
:
101 return self
.total_weight
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
113 def __init__(self
, stack_id
, ts
, cpu
, tid
, weight
, samp_type
, comm
):
114 self
.stack_id
= stack_id
119 self
.type = samp_type
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
132 ret
['sf'] = self
.stack_id
# Stack frame id
137 root_chain
= StackFrameNode(0, 'root', '[unknown]')
143 def process_event(param_dict
):
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
159 for cs
in param_dict
['cs']:
161 cs_dso
= os
.path
.basename(cs
[1])
162 cs_category
= FilterSymbolModule(cs_dso
)
163 cs_name
= FilterSymbolName(cs_category
, cs_dso
, cs_name
)
165 if cs_category
!= '<unknown>' or len(chain
) == 0:
166 sym
= (cs_name
, cs_category
)
168 while chain
[0] != sym
:
169 seen_syms
.remove(chain
[0])
173 chain
.appendleft(sym
)
175 # Discard garbage stacktrace before __pthread_start()
176 if cs_name
== '__pthread_start(void*)':
179 # Done reading call chain. Add to stack frame tree.
180 stack_frame
= root_chain
182 if call
in stack_frame
.children
:
183 stack_frame
= stack_frame
.children
[call
]
185 new_node
= StackFrameNode(next_stack_id
, call
[0], call
[1])
187 new_node
.parent_id
= stack_frame
.stack_id
188 stack_frame
.children
[call
] = new_node
189 stack_frame
= new_node
192 sample
= PerfSample(stack_frame
.stack_id
,
199 samples
.append(sample
)
200 stack_frame
.samples
.append(sample
)
201 saved_period
+= samp_period
209 # Return siblings of a call tree node.
210 def GetNodeSiblings(node
):
215 return node
.parent
.children
.values()
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.
221 parent_siblings
= GetNodeSiblings(parent
)
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:
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
)
237 # Recurse child nodes.
238 for c
in node
.children
.values():
241 FixCallTree(root_chain
, None)
244 trace_dict
['samples'] = [s
.ToDict() for s
in samples
]
245 trace_dict
['stackFrames'] = root_chain
.ToDict({})
246 trace_dict
['traceEvents'] = []
248 json
.dump(trace_dict
, sys
.stdout
, indent
=1)