PageRenderTime 33ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/edk2/ArmPlatformPkg/Scripts/Ds5/profile.py

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