4 # Copyright (c) 2014, ARM Limited. All rights reserved.
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 from cStringIO
import StringIO
28 print "-t,--trace: Location of the Trace file"
29 print "-s,--symbols: Location of the symbols and modules"
31 def get_address_from_string(address
):
32 return int(address
.strip("S:").strip("N:").strip("EL2:").strip("EL1:"), 16)
34 def get_module_from_addr(modules
, addr
):
35 for key
,value
in modules
.items():
36 if (value
['start'] <= addr
) and (addr
<= value
['end']):
40 def add_cycles_to_function(functions
, func_name
, addr
, cycles
):
41 if func_name
!= "<Unknown>":
42 # Check if we are still in the previous function
43 if add_cycles_to_function
.prev_func_name
== func_name
:
44 add_cycles_to_function
.prev_entry
['cycles'] += cycles
45 return (add_cycles_to_function
.prev_func_name
, add_cycles_to_function
.prev_module_name
)
47 if func_name
in functions
.keys():
48 for module_name
, module_value
in functions
[func_name
].iteritems():
49 if (module_value
['start'] <= addr
) and (addr
< module_value
['end']):
50 module_value
['cycles'] += cycles
52 add_cycles_to_function
.prev_func_name
= func_name
53 add_cycles_to_function
.prev_module_name
= module_name
54 add_cycles_to_function
.prev_entry
= module_value
55 return (func_name
, module_name
)
56 elif (module_value
['end'] == 0):
57 module_value
['cycles'] += cycles
59 add_cycles_to_function
.prev_func_name
= func_name
60 add_cycles_to_function
.prev_module_name
= module_name
61 add_cycles_to_function
.prev_entry
= module_value
62 return (func_name
, module_name
)
64 # Workaround to fix the 'info func' limitation that does not expose the 'static' function
65 module_name
= get_module_from_addr(modules
, addr
)
66 functions
[func_name
] = {}
67 functions
[func_name
][module_name
] = {}
68 functions
[func_name
][module_name
]['start'] = 0
69 functions
[func_name
][module_name
]['end'] = 0
70 functions
[func_name
][module_name
]['cycles'] = cycles
71 functions
[func_name
][module_name
]['count'] = 0
73 add_cycles_to_function
.prev_func_name
= func_name
74 add_cycles_to_function
.prev_module_name
= module_name
75 add_cycles_to_function
.prev_entry
= functions
[func_name
][module_name
]
76 return (func_name
, module_name
)
78 # Check if we are still in the previous function
79 if (add_cycles_to_function
.prev_entry
is not None) and (add_cycles_to_function
.prev_entry
['start'] <= addr
) and (addr
< add_cycles_to_function
.prev_entry
['end']):
80 add_cycles_to_function
.prev_entry
['cycles'] += cycles
81 return (add_cycles_to_function
.prev_func_name
, add_cycles_to_function
.prev_module_name
)
83 # Generate the key for the given address
86 if key
not in functions_addr
.keys():
87 if 'Unknown' not in functions
.keys():
88 functions
['Unknown'] = {}
89 if 'Unknown' not in functions
['Unknown'].keys():
90 functions
['Unknown']['Unknown'] = {}
91 functions
['Unknown']['Unknown']['cycles'] = 0
92 functions
['Unknown']['Unknown']['count'] = 0
93 functions
['Unknown']['Unknown']['cycles'] += cycles
95 add_cycles_to_function
.prev_func_name
= None
98 for func_key
, module
in functions_addr
[key
].iteritems():
99 for module_key
, module_value
in module
.iteritems():
100 if (module_value
['start'] <= addr
) and (addr
< module_value
['end']):
101 module_value
['cycles'] += cycles
103 # In case o <Unknown> we prefer to fallback on the direct search
104 add_cycles_to_function
.prev_func_name
= func_key
105 add_cycles_to_function
.prev_module_name
= module_key
106 add_cycles_to_function
.prev_entry
= module_value
107 return (func_key
, module_key
)
109 print "Warning: Function %s @ 0x%x not found" % (func_name
, addr
)
111 add_cycles_to_function
.prev_func_name
= None
114 # Static variables for the previous function
115 add_cycles_to_function
.prev_func_name
= None
116 add_cycles_to_function
.prev_entry
= None
120 line
= trace
.readline()
121 trace_process
+= len(line
)
130 opts
,args
= getopt
.getopt(sys
.argv
[1:], "ht:vs:v", ["help","trace=","symbols="])
131 if (opts
is None) or (not opts
):
136 if o
in ("-h","--help"):
139 elif o
in ("-t","--trace"):
141 elif o
in ("-s","--symbols"):
144 assert False, "Unhandled option (%s)" % o
147 # We try first to see if we run the script from DS-5
150 from arm_ds
.debugger_v1
import Debugger
151 from arm_ds
.debugger_v1
import DebugException
153 # Debugger object for accessing the debugger
154 debugger
= Debugger()
156 # Initialisation commands
157 ec
= debugger
.getExecutionContext(0)
158 ec
.getExecutionService().stop()
159 ec
.getExecutionService().waitForStop()
160 # in case the execution context reference is out of date
161 ec
= debugger
.getExecutionContext(0)
164 # Get the module name and their memory range
166 info_file
= ec
.executeDSCommand("info file")
167 info_file_str
= StringIO(info_file
)
169 line
= info_file_str
.readline().strip('\n')
171 if ("Symbols from" in line
):
172 # Get the module name from the line 'Symbols from "/home/...."'
173 module_name
= line
.split("\"")[1].split("/")[-1]
174 modules
[module_name
] = {}
176 # Look for the text section
177 line
= info_file_str
.readline().strip('\n')
178 while (line
!= '') and ("Symbols from" not in line
):
179 if ("ER_RO" in line
):
180 modules
[module_name
]['start'] = get_address_from_string(line
.split()[0])
181 modules
[module_name
]['end'] = get_address_from_string(line
.split()[2])
182 line
= info_file_str
.readline().strip('\n')
184 if (".text" in line
):
185 modules
[module_name
]['start'] = get_address_from_string(line
.split()[0])
186 modules
[module_name
]['end'] = get_address_from_string(line
.split()[2])
187 line
= info_file_str
.readline().strip('\n')
189 line
= info_file_str
.readline().strip('\n')
190 line
= info_file_str
.readline().strip('\n')
193 # Get the function name and their memory range
195 info_func
= ec
.executeDSCommand("info func")
196 info_func_str
= StringIO(info_func
)
198 # Skip the first line 'Low-level symbols ...'
199 line
= info_func_str
.readline().strip('\n')
202 # We ignore all the functions after 'Functions in'
203 if ("Functions in " in line
):
204 line
= info_func_str
.readline().strip('\n')
206 line
= info_func_str
.readline().strip('\n')
207 line
= info_func_str
.readline().strip('\n')
210 if ("Low-level symbols" in line
):
211 # We need to fixup the last function of the module
212 if func_prev
is not None:
213 func_prev
['end'] = modules
[module_name
]['end']
216 line
= info_func_str
.readline().strip('\n')
219 func_name
= line
.split()[1]
220 func_start
= get_address_from_string(line
.split()[0])
221 module_name
= get_module_from_addr(modules
, func_start
)
223 if func_name
not in functions
.keys():
224 functions
[func_name
] = {}
225 functions
[func_name
][module_name
] = {}
226 functions
[func_name
][module_name
]['start'] = func_start
227 functions
[func_name
][module_name
]['cycles'] = 0
228 functions
[func_name
][module_name
]['count'] = 0
230 # Set the end address of the previous function
231 if func_prev
is not None:
232 func_prev
['end'] = func_start
233 func_prev
= functions
[func_name
][module_name
]
235 line
= info_func_str
.readline().strip('\n')
237 # Fixup the last function
238 func_prev
['end'] = modules
[module_name
]['end']
240 if symbols_file
is not None:
241 pickle
.dump((modules
, functions
), open(symbols_file
, "w"))
243 if symbols_file
is None:
244 print "Error: Symbols file is required when run out of ARM DS-5"
247 (modules
, functions
) = pickle
.load(open(symbols_file
, "r"))
250 # Build optimized table for the <Unknown> functions
253 for func_key
, module
in functions
.iteritems():
254 for module_key
, module_value
in module
.iteritems():
255 key
= module_value
['start'] & ~
0x0FFF
256 if key
not in functions_addr
.keys():
257 functions_addr
[key
] = {}
258 if func_key
not in functions_addr
[key
].keys():
259 functions_addr
[key
][func_key
] = {}
260 functions_addr
[key
][func_key
][module_key
] = module_value
263 # Process the trace file
265 if trace_name
is None:
268 trace
= open(trace_name
, "r")
269 trace_size
= os
.path
.getsize(trace_name
)
272 # Get the column names from the first line
273 columns
= trace_read().split()
274 column_addr
= columns
.index('Address')
275 column_cycles
= columns
.index('Cycles')
276 column_function
= columns
.index('Function')
283 func_name
= line
.split('\t')[column_function
].strip()
284 address
= get_address_from_string(line
.split('\t')[column_addr
])
285 cycles
= int(line
.split('\t')[column_cycles
])
286 callee
= add_cycles_to_function(functions
, func_name
, address
, cycles
)
287 if (prev_callee
!= None) and (prev_callee
!= callee
):
288 functions
[prev_callee
[0]][prev_callee
[1]]['count'] += 1
293 if ((i
% 1000000) == 0) and (i
!= 0):
294 percent
= (trace_process
* 100.00) / trace_size
295 print "Processing file ... (%.2f %%)" % (percent
)
298 # Fixup the last callee
299 functions
[prev_callee
[0]][prev_callee
[1]]['count'] += 1
304 functions_cycles
= {}
305 all_functions_cycles
= {}
308 for func_key
, module
in functions
.iteritems():
309 for module_key
, module_value
in module
.iteritems():
310 key
= "%s/%s" % (module_key
, func_key
)
311 functions_cycles
[key
] = (module_value
['cycles'], module_value
['count'])
312 total_cycles
+= module_value
['cycles']
314 if func_key
not in all_functions_cycles
.keys():
315 all_functions_cycles
[func_key
] = (module_value
['cycles'], module_value
['count'])
317 all_functions_cycles
[func_key
] = tuple(map(sum, zip(all_functions_cycles
[func_key
], (module_value
['cycles'], module_value
['count']))))
319 sorted_functions_cycles
= sorted(functions_cycles
.iteritems(), key
=operator
.itemgetter(1), reverse
= True)
320 sorted_all_functions_cycles
= sorted(all_functions_cycles
.items(), key
=operator
.itemgetter(1), reverse
= True)
324 for (key
,value
) in sorted_functions_cycles
[:20]:
326 print "%s (cycles: %d - %d%%, count: %d)" % (key
, value
[0], (value
[0] * 100) / total_cycles
, value
[1])
330 for (key
,value
) in sorted_all_functions_cycles
[:20]:
332 print "%s (cycles: %d - %d%%, count: %d)" % (key
, value
[0], (value
[0] * 100) / total_cycles
, value
[1])