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