]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Scripts/Ds5/profile.py
ArmPlatformPkg: convert LFs to CRLF, expand hard TABs
[mirror_edk2.git] / ArmPlatformPkg / Scripts / Ds5 / profile.py
1 #!/usr/bin/python
2
3 #
4 # Copyright (c) 2014, ARM Limited. All rights reserved.
5 #
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
7 #
8
9 import getopt
10 import operator
11 import os
12 import pickle
13 import sys
14 from sys import argv
15 from cStringIO import StringIO
16
17 modules = {}
18 functions = {}
19 functions_addr = {}
20
21 def usage():
22 print "-t,--trace: Location of the Trace file"
23 print "-s,--symbols: Location of the symbols and modules"
24
25 def get_address_from_string(address):
26 return int(address.strip("S:").strip("N:").strip("EL2:").strip("EL1:"), 16)
27
28 def get_module_from_addr(modules, addr):
29 for key,value in modules.items():
30 if (value['start'] <= addr) and (addr <= value['end']):
31 return key
32 return None
33
34 def add_cycles_to_function(functions, func_name, addr, cycles):
35 if func_name != "<Unknown>":
36 # Check if we are still in the previous function
37 if add_cycles_to_function.prev_func_name == func_name:
38 add_cycles_to_function.prev_entry['cycles'] += cycles
39 return (add_cycles_to_function.prev_func_name, add_cycles_to_function.prev_module_name)
40
41 if func_name in functions.keys():
42 for module_name, module_value in functions[func_name].iteritems():
43 if (module_value['start'] <= addr) and (addr < module_value['end']):
44 module_value['cycles'] += cycles
45
46 add_cycles_to_function.prev_func_name = func_name
47 add_cycles_to_function.prev_module_name = module_name
48 add_cycles_to_function.prev_entry = module_value
49 return (func_name, module_name)
50 elif (module_value['end'] == 0):
51 module_value['cycles'] += cycles
52
53 add_cycles_to_function.prev_func_name = func_name
54 add_cycles_to_function.prev_module_name = module_name
55 add_cycles_to_function.prev_entry = module_value
56 return (func_name, module_name)
57
58 # Workaround to fix the 'info func' limitation that does not expose the 'static' function
59 module_name = get_module_from_addr(modules, addr)
60 functions[func_name] = {}
61 functions[func_name][module_name] = {}
62 functions[func_name][module_name]['start'] = 0
63 functions[func_name][module_name]['end'] = 0
64 functions[func_name][module_name]['cycles'] = cycles
65 functions[func_name][module_name]['count'] = 0
66
67 add_cycles_to_function.prev_func_name = func_name
68 add_cycles_to_function.prev_module_name = module_name
69 add_cycles_to_function.prev_entry = functions[func_name][module_name]
70 return (func_name, module_name)
71 else:
72 # Check if we are still in the previous function
73 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']):
74 add_cycles_to_function.prev_entry['cycles'] += cycles
75 return (add_cycles_to_function.prev_func_name, add_cycles_to_function.prev_module_name)
76
77 # Generate the key for the given address
78 key = addr & ~0x0FFF
79
80 if key not in functions_addr.keys():
81 if 'Unknown' not in functions.keys():
82 functions['Unknown'] = {}
83 if 'Unknown' not in functions['Unknown'].keys():
84 functions['Unknown']['Unknown'] = {}
85 functions['Unknown']['Unknown']['cycles'] = 0
86 functions['Unknown']['Unknown']['count'] = 0
87 functions['Unknown']['Unknown']['cycles'] += cycles
88
89 add_cycles_to_function.prev_func_name = None
90 return None
91
92 for func_key, module in functions_addr[key].iteritems():
93 for module_key, module_value in module.iteritems():
94 if (module_value['start'] <= addr) and (addr < module_value['end']):
95 module_value['cycles'] += cycles
96
97 # In case o <Unknown> we prefer to fallback on the direct search
98 add_cycles_to_function.prev_func_name = func_key
99 add_cycles_to_function.prev_module_name = module_key
100 add_cycles_to_function.prev_entry = module_value
101 return (func_key, module_key)
102
103 print "Warning: Function %s @ 0x%x not found" % (func_name, addr)
104
105 add_cycles_to_function.prev_func_name = None
106 return None
107
108 # Static variables for the previous function
109 add_cycles_to_function.prev_func_name = None
110 add_cycles_to_function.prev_entry = None
111
112 def trace_read():
113 global trace_process
114 line = trace.readline()
115 trace_process += len(line)
116 return line
117
118 #
119 # Parse arguments
120 #
121 trace_name = None
122 symbols_file = None
123
124 opts,args = getopt.getopt(sys.argv[1:], "ht:vs:v", ["help","trace=","symbols="])
125 if (opts is None) or (not opts):
126 usage()
127 sys.exit()
128
129 for o,a in opts:
130 if o in ("-h","--help"):
131 usage()
132 sys.exit()
133 elif o in ("-t","--trace"):
134 trace_name = a
135 elif o in ("-s","--symbols"):
136 symbols_file = a
137 else:
138 assert False, "Unhandled option (%s)" % o
139
140 #
141 # We try first to see if we run the script from DS-5
142 #
143 try:
144 from arm_ds.debugger_v1 import Debugger
145 from arm_ds.debugger_v1 import DebugException
146
147 # Debugger object for accessing the debugger
148 debugger = Debugger()
149
150 # Initialisation commands
151 ec = debugger.getExecutionContext(0)
152 ec.getExecutionService().stop()
153 ec.getExecutionService().waitForStop()
154 # in case the execution context reference is out of date
155 ec = debugger.getExecutionContext(0)
156
157 #
158 # Get the module name and their memory range
159 #
160 info_file = ec.executeDSCommand("info file")
161 info_file_str = StringIO(info_file)
162
163 line = info_file_str.readline().strip('\n')
164 while line != '':
165 if ("Symbols from" in line):
166 # Get the module name from the line 'Symbols from "/home/...."'
167 module_name = line.split("\"")[1].split("/")[-1]
168 modules[module_name] = {}
169
170 # Look for the text section
171 line = info_file_str.readline().strip('\n')
172 while (line != '') and ("Symbols from" not in line):
173 if ("ER_RO" in line):
174 modules[module_name]['start'] = get_address_from_string(line.split()[0])
175 modules[module_name]['end'] = get_address_from_string(line.split()[2])
176 line = info_file_str.readline().strip('\n')
177 break;
178 if (".text" in line):
179 modules[module_name]['start'] = get_address_from_string(line.split()[0])
180 modules[module_name]['end'] = get_address_from_string(line.split()[2])
181 line = info_file_str.readline().strip('\n')
182 break;
183 line = info_file_str.readline().strip('\n')
184 line = info_file_str.readline().strip('\n')
185
186 #
187 # Get the function name and their memory range
188 #
189 info_func = ec.executeDSCommand("info func")
190 info_func_str = StringIO(info_func)
191
192 # Skip the first line 'Low-level symbols ...'
193 line = info_func_str.readline().strip('\n')
194 func_prev = None
195 while line != '':
196 # We ignore all the functions after 'Functions in'
197 if ("Functions in " in line):
198 line = info_func_str.readline().strip('\n')
199 while line != '':
200 line = info_func_str.readline().strip('\n')
201 line = info_func_str.readline().strip('\n')
202 continue
203
204 if ("Low-level symbols" in line):
205 # We need to fixup the last function of the module
206 if func_prev is not None:
207 func_prev['end'] = modules[module_name]['end']
208 func_prev = None
209
210 line = info_func_str.readline().strip('\n')
211 continue
212
213 func_name = line.split()[1]
214 func_start = get_address_from_string(line.split()[0])
215 module_name = get_module_from_addr(modules, func_start)
216
217 if func_name not in functions.keys():
218 functions[func_name] = {}
219 functions[func_name][module_name] = {}
220 functions[func_name][module_name]['start'] = func_start
221 functions[func_name][module_name]['cycles'] = 0
222 functions[func_name][module_name]['count'] = 0
223
224 # Set the end address of the previous function
225 if func_prev is not None:
226 func_prev['end'] = func_start
227 func_prev = functions[func_name][module_name]
228
229 line = info_func_str.readline().strip('\n')
230
231 # Fixup the last function
232 func_prev['end'] = modules[module_name]['end']
233
234 if symbols_file is not None:
235 pickle.dump((modules, functions), open(symbols_file, "w"))
236 except:
237 if symbols_file is None:
238 print "Error: Symbols file is required when run out of ARM DS-5"
239 sys.exit()
240
241 (modules, functions) = pickle.load(open(symbols_file, "r"))
242
243 #
244 # Build optimized table for the <Unknown> functions
245 #
246 functions_addr = {}
247 for func_key, module in functions.iteritems():
248 for module_key, module_value in module.iteritems():
249 key = module_value['start'] & ~0x0FFF
250 if key not in functions_addr.keys():
251 functions_addr[key] = {}
252 if func_key not in functions_addr[key].keys():
253 functions_addr[key][func_key] = {}
254 functions_addr[key][func_key][module_key] = module_value
255
256 #
257 # Process the trace file
258 #
259 if trace_name is None:
260 sys.exit()
261
262 trace = open(trace_name, "r")
263 trace_size = os.path.getsize(trace_name)
264 trace_process = 0
265
266 # Get the column names from the first line
267 columns = trace_read().split()
268 column_addr = columns.index('Address')
269 column_cycles = columns.index('Cycles')
270 column_function = columns.index('Function')
271
272 line = trace_read()
273 i = 0
274 prev_callee = None
275 while line:
276 try:
277 func_name = line.split('\t')[column_function].strip()
278 address = get_address_from_string(line.split('\t')[column_addr])
279 cycles = int(line.split('\t')[column_cycles])
280 callee = add_cycles_to_function(functions, func_name, address, cycles)
281 if (prev_callee != None) and (prev_callee != callee):
282 functions[prev_callee[0]][prev_callee[1]]['count'] += 1
283 prev_callee = callee
284 except ValueError:
285 pass
286 line = trace_read()
287 if ((i % 1000000) == 0) and (i != 0):
288 percent = (trace_process * 100.00) / trace_size
289 print "Processing file ... (%.2f %%)" % (percent)
290 i = i + 1
291
292 # Fixup the last callee
293 functions[prev_callee[0]][prev_callee[1]]['count'] += 1
294
295 #
296 # Process results
297 #
298 functions_cycles = {}
299 all_functions_cycles = {}
300 total_cycles = 0
301
302 for func_key, module in functions.iteritems():
303 for module_key, module_value in module.iteritems():
304 key = "%s/%s" % (module_key, func_key)
305 functions_cycles[key] = (module_value['cycles'], module_value['count'])
306 total_cycles += module_value['cycles']
307
308 if func_key not in all_functions_cycles.keys():
309 all_functions_cycles[func_key] = (module_value['cycles'], module_value['count'])
310 else:
311 all_functions_cycles[func_key] = tuple(map(sum, zip(all_functions_cycles[func_key], (module_value['cycles'], module_value['count']))))
312
313 sorted_functions_cycles = sorted(functions_cycles.iteritems(), key=operator.itemgetter(1), reverse = True)
314 sorted_all_functions_cycles = sorted(all_functions_cycles.items(), key=operator.itemgetter(1), reverse = True)
315
316 print
317 print "----"
318 for (key,value) in sorted_functions_cycles[:20]:
319 if value[0] != 0:
320 print "%s (cycles: %d - %d%%, count: %d)" % (key, value[0], (value[0] * 100) / total_cycles, value[1])
321 else:
322 break;
323 print "----"
324 for (key,value) in sorted_all_functions_cycles[:20]:
325 if value[0] != 0:
326 print "%s (cycles: %d - %d%%, count: %d)" % (key, value[0], (value[0] * 100) / total_cycles, value[1])
327 else:
328 break;