mirror of https://github.com/acidanthera/audk.git
ArmPlatformPkg/Ds5: Added script to profile EDK2 with ARM DSTREAM
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15550 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
451b665890
commit
8b7f930a14
|
@ -0,0 +1,316 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#
|
||||
# Copyright (c) 2014, ARM Limited. All rights reserved.
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
|
||||
import getopt
|
||||
import operator
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
from sys import argv
|
||||
from cStringIO import StringIO
|
||||
|
||||
modules = {}
|
||||
functions = {}
|
||||
functions_addr = {}
|
||||
|
||||
def usage():
|
||||
print "-t,--trace: Location of the Trace file"
|
||||
print "-s,--symbols: Location of the symbols and modules"
|
||||
|
||||
def get_module_from_addr(modules, addr):
|
||||
for key,value in modules.items():
|
||||
if (value['start'] <= addr) and (addr <= value['end']):
|
||||
return key
|
||||
return None
|
||||
|
||||
def add_cycles_to_function(functions, func_name, addr, cycles):
|
||||
if func_name != "<Unknown>":
|
||||
# Check if we are still in the previous function
|
||||
if add_cycles_to_function.prev_func_name == func_name:
|
||||
add_cycles_to_function.prev_entry['cycles'] += cycles
|
||||
return (add_cycles_to_function.prev_func_name, add_cycles_to_function.prev_module_name)
|
||||
|
||||
if func_name in functions.keys():
|
||||
for module_name, module_value in functions[func_name].iteritems():
|
||||
if (module_value['start'] <= addr) and (addr < module_value['end']):
|
||||
module_value['cycles'] += cycles
|
||||
|
||||
add_cycles_to_function.prev_func_name = func_name
|
||||
add_cycles_to_function.prev_module_name = module_name
|
||||
add_cycles_to_function.prev_entry = module_value
|
||||
return (func_name, module_name)
|
||||
elif (module_value['end'] == 0):
|
||||
module_value['cycles'] += cycles
|
||||
|
||||
add_cycles_to_function.prev_func_name = func_name
|
||||
add_cycles_to_function.prev_module_name = module_name
|
||||
add_cycles_to_function.prev_entry = module_value
|
||||
return (func_name, module_name)
|
||||
|
||||
# Workaround to fix the 'info func' limitation that does not expose the 'static' function
|
||||
module_name = get_module_from_addr(modules, addr)
|
||||
functions[func_name] = {}
|
||||
functions[func_name][module_name] = {}
|
||||
functions[func_name][module_name]['start'] = 0
|
||||
functions[func_name][module_name]['end'] = 0
|
||||
functions[func_name][module_name]['cycles'] = cycles
|
||||
functions[func_name][module_name]['count'] = 0
|
||||
|
||||
add_cycles_to_function.prev_func_name = func_name
|
||||
add_cycles_to_function.prev_module_name = module_name
|
||||
add_cycles_to_function.prev_entry = functions[func_name][module_name]
|
||||
return (func_name, module_name)
|
||||
else:
|
||||
# Check if we are still in the previous function
|
||||
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']):
|
||||
add_cycles_to_function.prev_entry['cycles'] += cycles
|
||||
return (add_cycles_to_function.prev_func_name, add_cycles_to_function.prev_module_name)
|
||||
|
||||
# Generate the key for the given address
|
||||
key = addr & ~0x0FFF
|
||||
|
||||
if key not in functions_addr.keys():
|
||||
if 'Unknown' not in functions.keys():
|
||||
functions['Unknown'] = {}
|
||||
if 'Unknown' not in functions['Unknown'].keys():
|
||||
functions['Unknown']['Unknown'] = {}
|
||||
functions['Unknown']['Unknown']['cycles'] = 0
|
||||
functions['Unknown']['Unknown']['count'] = 0
|
||||
functions['Unknown']['Unknown']['cycles'] += cycles
|
||||
|
||||
add_cycles_to_function.prev_func_name = None
|
||||
return None
|
||||
|
||||
for func_key, module in functions_addr[key].iteritems():
|
||||
for module_key, module_value in module.iteritems():
|
||||
if (module_value['start'] <= addr) and (addr < module_value['end']):
|
||||
module_value['cycles'] += cycles
|
||||
|
||||
# In case o <Unknown> we prefer to fallback on the direct search
|
||||
add_cycles_to_function.prev_func_name = func_key
|
||||
add_cycles_to_function.prev_module_name = module_key
|
||||
add_cycles_to_function.prev_entry = module_value
|
||||
return (func_key, module_key)
|
||||
|
||||
print "Warning: Function %s @ 0x%x not found" % (func_name, addr)
|
||||
|
||||
add_cycles_to_function.prev_func_name = None
|
||||
return None
|
||||
|
||||
# Static variables for the previous function
|
||||
add_cycles_to_function.prev_func_name = None
|
||||
add_cycles_to_function.prev_entry = None
|
||||
|
||||
def trace_read():
|
||||
global trace_process
|
||||
line = trace.readline()
|
||||
trace_process += len(line)
|
||||
return line
|
||||
|
||||
#
|
||||
# Parse arguments
|
||||
#
|
||||
trace_name = None
|
||||
symbols_file = None
|
||||
|
||||
opts,args = getopt.getopt(sys.argv[1:], "ht:vs:v", ["help","trace=","symbols="])
|
||||
if (opts is None) or (not opts):
|
||||
usage()
|
||||
sys.exit()
|
||||
|
||||
for o,a in opts:
|
||||
if o in ("-h","--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
elif o in ("-t","--trace"):
|
||||
trace_name = a
|
||||
elif o in ("-s","--symbols"):
|
||||
symbols_file = a
|
||||
else:
|
||||
assert False, "Unhandled option (%s)" % o
|
||||
|
||||
#
|
||||
# We try first to see if we run the script from DS-5
|
||||
#
|
||||
try:
|
||||
from arm_ds.debugger_v1 import Debugger
|
||||
from arm_ds.debugger_v1 import DebugException
|
||||
|
||||
# Debugger object for accessing the debugger
|
||||
debugger = Debugger()
|
||||
|
||||
# Initialisation commands
|
||||
ec = debugger.getExecutionContext(0)
|
||||
ec.getExecutionService().stop()
|
||||
ec.getExecutionService().waitForStop()
|
||||
# in case the execution context reference is out of date
|
||||
ec = debugger.getExecutionContext(0)
|
||||
|
||||
#
|
||||
# Get the module name and their memory range
|
||||
#
|
||||
info_file = ec.executeDSCommand("info file")
|
||||
info_file_str = StringIO(info_file)
|
||||
|
||||
line = info_file_str.readline().strip('\n')
|
||||
while line != '':
|
||||
if ("Symbols from" in line):
|
||||
# Get the module name from the line 'Symbols from "/home/...."'
|
||||
module_name = line.split("\"")[1].split("/")[-1]
|
||||
modules[module_name] = {}
|
||||
|
||||
# Look for the text section
|
||||
line = info_file_str.readline().strip('\n')
|
||||
while (line != '') and ("Symbols from" not in line):
|
||||
if ("ER_RO" in line):
|
||||
modules[module_name]['start'] = int(line.split()[0].strip("S:"), 16)
|
||||
modules[module_name]['end'] = int(line.split()[2].strip("S:"), 16)
|
||||
line = info_file_str.readline().strip('\n')
|
||||
break;
|
||||
line = info_file_str.readline().strip('\n')
|
||||
line = info_file_str.readline().strip('\n')
|
||||
|
||||
#
|
||||
# Get the function name and their memory range
|
||||
#
|
||||
info_func = ec.executeDSCommand("info func")
|
||||
info_func_str = StringIO(info_func)
|
||||
|
||||
# Skip the first line 'Low-level symbols ...'
|
||||
line = info_func_str.readline().strip('\n')
|
||||
func_prev = None
|
||||
while line != '':
|
||||
if ("Low-level symbols" in line):
|
||||
# We need to fixup the last function of the module
|
||||
if func_prev is not None:
|
||||
func_prev['end'] = modules[module_name]['end']
|
||||
func_prev = None
|
||||
|
||||
line = info_func_str.readline().strip('\n')
|
||||
continue
|
||||
func_name = line.split()[1]
|
||||
func_start = int(line.split()[0].strip("S:"), 16)
|
||||
module_name = get_module_from_addr(modules, func_start)
|
||||
if func_name not in functions.keys():
|
||||
functions[func_name] = {}
|
||||
functions[func_name][module_name] = {}
|
||||
functions[func_name][module_name]['start'] = func_start
|
||||
functions[func_name][module_name]['cycles'] = 0
|
||||
functions[func_name][module_name]['count'] = 0
|
||||
|
||||
# Set the end address of the previous function
|
||||
if func_prev is not None:
|
||||
func_prev['end'] = func_start
|
||||
func_prev = functions[func_name][module_name]
|
||||
|
||||
line = info_func_str.readline().strip('\n')
|
||||
|
||||
# Fixup the last function
|
||||
func_prev['end'] = modules[module_name]['end']
|
||||
|
||||
if symbols_file is not None:
|
||||
pickle.dump((modules, functions), open(symbols_file, "w"))
|
||||
except:
|
||||
if symbols_file is None:
|
||||
print "Error: Symbols file is required when run out of ARM DS-5"
|
||||
sys.exit()
|
||||
|
||||
(modules, functions) = pickle.load(open(symbols_file, "r"))
|
||||
|
||||
#
|
||||
# Build optimized table for the <Unknown> functions
|
||||
#
|
||||
functions_addr = {}
|
||||
for func_key, module in functions.iteritems():
|
||||
for module_key, module_value in module.iteritems():
|
||||
key = module_value['start'] & ~0x0FFF
|
||||
if key not in functions_addr.keys():
|
||||
functions_addr[key] = {}
|
||||
if func_key not in functions_addr[key].keys():
|
||||
functions_addr[key][func_key] = {}
|
||||
functions_addr[key][func_key][module_key] = module_value
|
||||
|
||||
#
|
||||
# Process the trace file
|
||||
#
|
||||
if trace_name is None:
|
||||
sys.exit()
|
||||
|
||||
trace = open(trace_name, "r")
|
||||
trace_size = os.path.getsize(trace_name)
|
||||
trace_process = 0
|
||||
|
||||
# Get the column names from the first line
|
||||
columns = trace_read().split()
|
||||
column_addr = columns.index('Address')
|
||||
column_cycles = columns.index('Cycles')
|
||||
column_function = columns.index('Function')
|
||||
|
||||
line = trace_read()
|
||||
i = 0
|
||||
prev_callee = None
|
||||
while line:
|
||||
try:
|
||||
func_name = line.split('\t')[column_function].strip()
|
||||
address = int(line.split('\t')[column_addr].strip("S:"), 16)
|
||||
cycles = int(line.split('\t')[column_cycles])
|
||||
callee = add_cycles_to_function(functions, func_name, address, cycles)
|
||||
if (prev_callee != None) and (prev_callee != callee):
|
||||
functions[prev_callee[0]][prev_callee[1]]['count'] += 1
|
||||
prev_callee = callee
|
||||
except ValueError:
|
||||
pass
|
||||
line = trace_read()
|
||||
if ((i % 1000000) == 0) and (i != 0):
|
||||
percent = (trace_process * 100.00) / trace_size
|
||||
print "Processing file ... (%.2f %%)" % (percent)
|
||||
i = i + 1
|
||||
|
||||
# Fixup the last callee
|
||||
functions[prev_callee[0]][prev_callee[1]]['count'] += 1
|
||||
|
||||
#
|
||||
# Process results
|
||||
#
|
||||
functions_cycles = {}
|
||||
all_functions_cycles = {}
|
||||
total_cycles = 0
|
||||
|
||||
for func_key, module in functions.iteritems():
|
||||
for module_key, module_value in module.iteritems():
|
||||
key = "%s/%s" % (module_key, func_key)
|
||||
functions_cycles[key] = (module_value['cycles'], module_value['count'])
|
||||
total_cycles += module_value['cycles']
|
||||
|
||||
if func_key not in all_functions_cycles.keys():
|
||||
all_functions_cycles[func_key] = (module_value['cycles'], module_value['count'])
|
||||
else:
|
||||
all_functions_cycles[func_key] = tuple(map(sum, zip(all_functions_cycles[func_key], (module_value['cycles'], module_value['count']))))
|
||||
|
||||
sorted_functions_cycles = sorted(functions_cycles.iteritems(), key=operator.itemgetter(1), reverse = True)
|
||||
sorted_all_functions_cycles = sorted(all_functions_cycles.items(), key=operator.itemgetter(1), reverse = True)
|
||||
|
||||
print
|
||||
print "----"
|
||||
for (key,value) in sorted_functions_cycles[:20]:
|
||||
if value[0] != 0:
|
||||
print "%s (cycles: %d - %d%%, count: %d)" % (key, value[0], (value[0] * 100) / total_cycles, value[1])
|
||||
else:
|
||||
break;
|
||||
print "----"
|
||||
for (key,value) in sorted_all_functions_cycles[:20]:
|
||||
if value[0] != 0:
|
||||
print "%s (cycles: %d - %d%%, count: %d)" % (key, value[0], (value[0] * 100) / total_cycles, value[1])
|
||||
else:
|
||||
break;
|
Loading…
Reference in New Issue