# -*- Mode: Python -*- import os import re # 08135174 00000041 T PyRun_SimpleString fun_re = re.compile ('([0-9a-f]+) ([0-9a-f]+) [Tt] ([0-9A-Za-z_]+)\n') def get_syms (path_exe): p = os.popen ('nm -S %s' % (path_exe,), 'r') d = {} while 1: line = p.readline() if not line: break else: probe = fun_re.match (line) if probe is not None: addr, size, name = probe.groups() d[int(addr,16)] = (name, int(size,16)) return d def get_sym (syms, addr): if syms.has_key (addr): return syms[addr][0] else: return hex(addr) def read_profile (path_prof): graph = {} f = open (path_prof, 'rb') while 1: line = f.readline() if not line or line[0] == '-': break else: addr, count, ticks = line.split() addr = int (addr, 16) count = int (count) ticks = int (ticks) graph[addr] = (count, ticks, []) line = f.readline() while 1: # read fun address if not line: break else: caller = int(line,16) callees = graph[caller][2] while 1: line = f.readline() if not line: break elif line[0] == ' ': addr, count = line.split() addr = int(addr, 16) count = int (count) callees.append ((addr, count)) else: break return graph def print_profile (syms, graph, sortby='ticks'): # pull out ticks and counts profile = [(t, c, a) for (a, (c, t, ignore)) in graph.iteritems()] # convert addresses to names profile = [(t, c, get_sym(syms,a)) for (t, c, a) in profile] # repair zero-count entries profile = [(t, c or 1, n) for (t,c,n) in profile] # synthesize ticks/call profile = [(t, c, t/c, n) for (t,c,n) in profile] which = {'ticks':0, 'count':1, 'tpc':2, 'name':3}[sortby] profile.sort (lambda a,b: cmp(a[which],b[which])) sum_ticks = 0 sum_calls = 0 for ticks, count, per, name in profile: sum_ticks += ticks sum_calls += count sum_percent = 0 for ticks, count, per, name in profile: percent = 100 * (ticks / float(sum_ticks)) print '%15d %6.2f %12d %10d %s' % ( ticks, percent, count, per, name ) sum_percent += percent print '%15d %6.2f %12d %10s (totals)' % ( sum_ticks, sum_percent, sum_calls, '' ) def print_graph (syms, graph): # we have the forward graph, build the reverse from it rg = {} for addr, (total_count, ticks, callees) in graph.iteritems(): for callee, count in callees: if rg.has_key (callee): rg[callee].append ((addr, count)) else: rg[callee] = [(addr, count)] # gi = graph.items() gi.sort() for addr, (total_count, ticks, callees) in gi: print '------------------------------' if rg.has_key (addr): for caller, count in rg[addr]: print ' %8s %8d %s' % ('', count, get_sym (syms, caller)) print '%8d %s' % (total_count, get_sym (syms, addr)) for callee, count in callees: if (callee == addr): print ' %8s %8d [recursive]' % ('', count,) else: print ' %8s %8d %s' % ('', count, get_sym (syms, callee)) def print_profile_html (syms, graph): # pull out ticks and counts profile = [(t, c, a) for (a, (c, t, ignore)) in graph.iteritems()] # convert addresses to names profile = [(t, c, get_sym(syms,a)) for (t, c, a) in profile] # repair zero-count entries profile = [(t, c or 1, n) for (t,c,n) in profile] # synthesize ticks/call profile = [(t, c, t/c, n) for (t,c,n) in profile] # sortby == ticks which = 0 profile.sort (lambda a,b: cmp(b[which],a[which])) sum_ticks = 0 sum_calls = 0 for ticks, count, per, name in profile: sum_ticks += ticks sum_calls += count print '' print '' i = 0 for ticks, count, per, name in profile: percent = 100 * (ticks / float(sum_ticks)) print ( '' '' '' '' '' '' '' % ( ticks, percent, count, per, name, name, name ) ) i += 1 print '' % ( sum_ticks, 100.00, sum_calls ) print '
tickspercentcallsticks/callfunction
%d%6.2f%d%d%s
%d%6.2f%d(totals)
' def print_graph_html (syms, graph): # we have the forward graph, build the reverse from it rg = {} for addr, (total_count, ticks, callees) in graph.iteritems(): for callee, count in callees: if rg.has_key (callee): rg[callee].append ((addr, count)) else: rg[callee] = [(addr, count)] # gi = [(get_sym (syms, x[0]), x) for x in graph.iteritems()] gi.sort() for name, (addr, (total_count, ticks, callees)) in gi: print '
' print '%s [%d]' % (name, name, ticks) print '
'
        if rg.has_key (addr):
            l = []
            for caller, count in rg[addr]:
                cname = get_sym (syms, caller)
                tc, tt, cl = graph[addr]
                est_ticks = (ticks * count) / total_count
                l.append ((count, tc, est_ticks, cname))
            l.sort (lambda a,b:cmp(a[2],b[2]))
            for count, tc, est_ticks, cname in l:
                print '%10d/%-10d %15d %s' % (count, tc, est_ticks, cname, cname)
        print '%15d %15d %s' % (total_count, ticks, name)
        callees2 = []
        for callee, count in callees:
            cname = get_sym (syms, callee)
            tc, tt, cl = graph[callee]
            est_ticks = (tt / tc) * count
            callees2.append ((count, tc, est_ticks, cname))
        # sort by estimated ticks
        callees2.sort (lambda a,b: cmp (b[2], a[2]))
        for count, tc, est_ticks, cname in callees2:
            print '%10d/%-10d %15d %s' % (count, tc, est_ticks, cname, cname)
        print '
' def print_html (syms, graph): print 'tscprof results' print '

tscprof results

' print_profile_html (syms, graph) print_graph_html (syms, graph) print '' if __name__ == '__main__': import sys if '-html' in sys.argv: sys.argv.remove ('-html') html = True else: html = False if len(sys.argv) > 3: sortby = sys.argv[3] else: sortby = 'ticks' syms = get_syms (sys.argv[1]) graph = read_profile (sys.argv[2]) if html: print_html (syms, graph) else: print_profile (syms, graph, sortby) print_graph (syms, graph)