# by snikim from __future__ import division import sys, os import re prefix = sys.argv[1] disinp = open(prefix + '.dis') profinp = open(prefix + '.out') pat_prof = re.compile('^0x([0-9a-f]{4,6}) ([0-9]+) ([0-9.]+)$') pat_dis = re.compile('^ +([0-9a-f]{4,6}):[ \t]+[0-9a-f]+[ \t]+([a-zA-Z0-9_-]+)[ \t]+(.*)$') CANONICALINSTRS = { } CONDITIONALS = ('eq', 'ne', 'cs', 'hs', 'cc', 'lo', 'mi', 'pl', 'vs', 'vc', 'hi', 'ls', 'ge', 'lt', 'gt', 'le', 'al') CONDITIONAL_INSTRS = ( 'adc', 'adc_s', 'add', 'add_s', 'and', 'b', 'bl', 'bic', 'blx', 'bx', 'cdp', 'clz', 'cmn', 'cmp', 'eor', 'ldc', 'ldm', 'ldm_ia', 'ldm_db', 'ldr', 'ldr_b', 'ldr_bt', 'ldr_h', 'ldr_sb', 'ldr_sh', 'ldr_t', 'mcr', 'mla', 'mla_s', 'mov', 'mov_s', 'mrc', 'mrs', 'msr', 'mul', 'mul_s', 'mvn', 'mvn_s', 'orr', 'orr_s', 'rsb', 'rsb_s', 'rsc', 'rsc_s', 'sbc', 'sbc_s', 'smlal', 'smlal_s', 'smull', 'smull_s', 'stc', 'stc_l', 'stm', 'stm_p' ,'stm_u', 'stm_db', 'stm_w', 'str', 'str_b', 'str_bt', 'str_h', 'str_t', 'sub', 'sub_s', 'swi', 'swp', 'swp_b', 'teq', 'tst', 'umlal', 'umlal_s', 'umull', 'umull_s', ) for cond in CONDITIONALS: for instr in CONDITIONAL_INSTRS: if '_' in instr: pfx = instr.split('_')[0] CANONICALINSTRS[instr.replace('_', '')] = pfx CANONICALINSTRS[instr.replace('_', cond)] = pfx else: CANONICALINSTRS[instr + cond] = instr CANONICALINSTRS.update({ 'bics': 'bic', }) addrprofs = {} for l in profinp: l = l[:-1] match = pat_prof.match(l) if match is not None: addr, count, percent = match.groups() addr = int(addr, 16) addrprofs[addr] = {'count': int(count)} unused = 0 for l in disinp: l = l[:-1] match = pat_dis.match(l) if match is not None: addr, instr, operands = match.groups() addr = int(addr, 16) if addr not in addrprofs: addrprofs[addr] = {'count': 0} unused += 1 addrprofs[addr]['instr'] = instr addrprofs[addr]['operands'] = operands profs = addrprofs.items() profs.sort(key=lambda (k, v): (v['count'], k), reverse=True) totalcalls = sum(v['count'] for k, v in profs) print "==== basic statistics ====" print " Total calls:\t\t\t%12d" % totalcalls print " Total lines of the code:\t%12d" % len(profs) print " Unused code:\t\t\t%12d (%6.2f%%)" % (unused, unused / len(profs) * 100) print perinstr = {} for addr, info in profs: instr = CANONICALINSTRS.get(info['instr'], info['instr']) if instr not in perinstr: perinstr[instr] = 0 perinstr[instr] += info['count'] perinstr = perinstr.items() perinstr.sort(key=lambda (k, v): (v, k), reverse=True) print "==== frequent instructions ====" accum = 0 for instr, freq in perinstr[:20]: accum += freq print "%s\t%10d\t%6.2f%%\t%6.2f%%" % (instr, freq, freq/totalcalls*100, accum/totalcalls*100) print print "==== per-code statistics ====" accumcalls = 0 for i, (addr, info) in enumerate(profs): accumcalls += info['count'] print '%6d\t%6.2f%%\t%12d\t%6.2f%%\t%12d\t0x%08x\t%s\t%s' % ( i, i / len(profs) * 100.0, accumcalls, accumcalls / totalcalls * 100.0, info['count'], addr, info['instr'], info['operands'], ) # ex: ts=8 sts=4 sw=4 et