]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Scripts/Ds5/profile.py
MdeModulePkg/DxeCore: Add UEFI image protection.
[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 # 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
10 #
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.
13 #
14
15 import getopt
16 import operator
17 import os
18 import pickle
19 import sys
20 from sys import argv
21 from cStringIO import StringIO
22
23 modules = {}
24 functions = {}
25 functions_addr = {}
26
27 def usage():
28 print "-t,--trace: Location of the Trace file"
29 print "-s,--symbols: Location of the symbols and modules"
30
31 def get_address_from_string(address):
32 return int(address.strip("S:").strip("N:").strip("EL2:").strip("EL1:"), 16)
33
34 def get_module_from_addr(modules, addr):
35 for key,value in modules.items():
36 if (value['start'] <= addr) and (addr <= value['end']):
37 return key
38 return None
39
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)
46
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
51
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
58
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)
63
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
72
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)
77 else:
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)
82
83 # Generate the key for the given address
84 key = addr & ~0x0FFF
85
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
94
95 add_cycles_to_function.prev_func_name = None
96 return None
97
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
102
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)
108
109 print "Warning: Function %s @ 0x%x not found" % (func_name, addr)
110
111 add_cycles_to_function.prev_func_name = None
112 return None
113
114 # Static variables for the previous function
115 add_cycles_to_function.prev_func_name = None
116 add_cycles_to_function.prev_entry = None
117
118 def trace_read():
119 global trace_process
120 line = trace.readline()
121 trace_process += len(line)
122 return line
123
124 #
125 # Parse arguments
126 #
127 trace_name = None
128 symbols_file = None
129
130 opts,args = getopt.getopt(sys.argv[1:], "ht:vs:v", ["help","trace=","symbols="])
131 if (opts is None) or (not opts):
132 usage()
133 sys.exit()
134
135 for o,a in opts:
136 if o in ("-h","--help"):
137 usage()
138 sys.exit()
139 elif o in ("-t","--trace"):
140 trace_name = a
141 elif o in ("-s","--symbols"):
142 symbols_file = a
143 else:
144 assert False, "Unhandled option (%s)" % o
145
146 #
147 # We try first to see if we run the script from DS-5
148 #
149 try:
150 from arm_ds.debugger_v1 import Debugger
151 from arm_ds.debugger_v1 import DebugException
152
153 # Debugger object for accessing the debugger
154 debugger = Debugger()
155
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)
162
163 #
164 # Get the module name and their memory range
165 #
166 info_file = ec.executeDSCommand("info file")
167 info_file_str = StringIO(info_file)
168
169 line = info_file_str.readline().strip('\n')
170 while line != '':
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] = {}
175
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')
183 break;
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')
188 break;
189 line = info_file_str.readline().strip('\n')
190 line = info_file_str.readline().strip('\n')
191
192 #
193 # Get the function name and their memory range
194 #
195 info_func = ec.executeDSCommand("info func")
196 info_func_str = StringIO(info_func)
197
198 # Skip the first line 'Low-level symbols ...'
199 line = info_func_str.readline().strip('\n')
200 func_prev = None
201 while line != '':
202 # We ignore all the functions after 'Functions in'
203 if ("Functions in " in line):
204 line = info_func_str.readline().strip('\n')
205 while line != '':
206 line = info_func_str.readline().strip('\n')
207 line = info_func_str.readline().strip('\n')
208 continue
209
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']
214 func_prev = None
215
216 line = info_func_str.readline().strip('\n')
217 continue
218
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)
222
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
229
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]
234
235 line = info_func_str.readline().strip('\n')
236
237 # Fixup the last function
238 func_prev['end'] = modules[module_name]['end']
239
240 if symbols_file is not None:
241 pickle.dump((modules, functions), open(symbols_file, "w"))
242 except:
243 if symbols_file is None:
244 print "Error: Symbols file is required when run out of ARM DS-5"
245 sys.exit()
246
247 (modules, functions) = pickle.load(open(symbols_file, "r"))
248
249 #
250 # Build optimized table for the <Unknown> functions
251 #
252 functions_addr = {}
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
261
262 #
263 # Process the trace file
264 #
265 if trace_name is None:
266 sys.exit()
267
268 trace = open(trace_name, "r")
269 trace_size = os.path.getsize(trace_name)
270 trace_process = 0
271
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')
277
278 line = trace_read()
279 i = 0
280 prev_callee = None
281 while line:
282 try:
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
289 prev_callee = callee
290 except ValueError:
291 pass
292 line = trace_read()
293 if ((i % 1000000) == 0) and (i != 0):
294 percent = (trace_process * 100.00) / trace_size
295 print "Processing file ... (%.2f %%)" % (percent)
296 i = i + 1
297
298 # Fixup the last callee
299 functions[prev_callee[0]][prev_callee[1]]['count'] += 1
300
301 #
302 # Process results
303 #
304 functions_cycles = {}
305 all_functions_cycles = {}
306 total_cycles = 0
307
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']
313
314 if func_key not in all_functions_cycles.keys():
315 all_functions_cycles[func_key] = (module_value['cycles'], module_value['count'])
316 else:
317 all_functions_cycles[func_key] = tuple(map(sum, zip(all_functions_cycles[func_key], (module_value['cycles'], module_value['count']))))
318
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)
321
322 print
323 print "----"
324 for (key,value) in sorted_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;
329 print "----"
330 for (key,value) in sorted_all_functions_cycles[:20]:
331 if value[0] != 0:
332 print "%s (cycles: %d - %d%%, count: %d)" % (key, value[0], (value[0] * 100) / total_cycles, value[1])
333 else:
334 break;