win32kprof: Convert tabs to spaces.

This commit is contained in:
José Fonseca
2008-07-21 13:02:07 +09:00
parent 1662be3764
commit ac25408c47

View File

@@ -37,262 +37,262 @@ __version__ = '0.1'
class ParseError(Exception): class ParseError(Exception):
pass pass
class MsvcDemangler: class MsvcDemangler:
# http://www.kegel.com/mangle.html # http://www.kegel.com/mangle.html
def __init__(self, symbol): def __init__(self, symbol):
self._symbol = symbol self._symbol = symbol
self._pos = 0 self._pos = 0
def lookahead(self): def lookahead(self):
return self._symbol[self._pos] return self._symbol[self._pos]
def consume(self): def consume(self):
ret = self.lookahead() ret = self.lookahead()
self._pos += 1 self._pos += 1
return ret return ret
def match(self, c): def match(self, c):
if self.lookahead() != c: if self.lookahead() != c:
raise ParseError raise ParseError
self.consume() self.consume()
def parse(self): def parse(self):
self.match('?') self.match('?')
name = self.parse_name() name = self.parse_name()
qualifications = self.parse_qualifications() qualifications = self.parse_qualifications()
return '::'.join(qualifications + [name]) return '::'.join(qualifications + [name])
def parse_name(self): def parse_name(self):
if self.lookahead() == '?': if self.lookahead() == '?':
return self.consume() + self.consume() return self.consume() + self.consume()
else: else:
name = self.parse_id() name = self.parse_id()
self.match('@') self.match('@')
return name return name
def parse_qualifications(self): def parse_qualifications(self):
qualifications = [] qualifications = []
while self.lookahead() != '@': while self.lookahead() != '@':
name = self.parse_id() name = self.parse_id()
qualifications.append(name) qualifications.append(name)
self.match('@') self.match('@')
return qualifications return qualifications
def parse_id(self): def parse_id(self):
s = '' s = ''
while True: while True:
c = self.lookahead() c = self.lookahead()
if c.isalnum() or c in '_': if c.isalnum() or c in '_':
s += c s += c
self.consume() self.consume()
else: else:
break break
return s return s
def demangle(name): def demangle(name):
if name.startswith('_'): if name.startswith('_'):
name = name[1:] name = name[1:]
idx = name.rfind('@') idx = name.rfind('@')
if idx != -1 and name[idx+1:].isdigit(): if idx != -1 and name[idx+1:].isdigit():
name = name[:idx] name = name[:idx]
return name return name
if name.startswith('?'): if name.startswith('?'):
demangler = MsvcDemangler(name) demangler = MsvcDemangler(name)
return demangler.parse() return demangler.parse()
return name return name
return name return name
class Profile: class Profile:
def __init__(self): def __init__(self):
self.symbols = [] self.symbols = []
self.symbol_cache = {} self.symbol_cache = {}
self.base_addr = None self.base_addr = None
self.functions = {} self.functions = {}
self.last_stamp = 0 self.last_stamp = 0
self.stamp_base = 0 self.stamp_base = 0
def unwrap_stamp(self, stamp): def unwrap_stamp(self, stamp):
if stamp < self.last_stamp: if stamp < self.last_stamp:
self.stamp_base += 1 << 32 self.stamp_base += 1 << 32
self.last_stamp = stamp self.last_stamp = stamp
return self.stamp_base + stamp return self.stamp_base + stamp
def read_map(self, mapfile): def read_map(self, mapfile):
# See http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx # See http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
last_addr = 0 last_addr = 0
last_name = 0 last_name = 0
for line in file(mapfile, "rt"): for line in file(mapfile, "rt"):
fields = line.split() fields = line.split()
try: try:
section_offset, name, addr, type, lib_object = fields section_offset, name, addr, type, lib_object = fields
except ValueError: except ValueError:
continue continue
if type != 'f': if type != 'f':
continue continue
section, offset = section_offset.split(':') section, offset = section_offset.split(':')
addr = int(offset, 16) addr = int(offset, 16)
name = demangle(name) name = demangle(name)
if last_addr == addr: if last_addr == addr:
# TODO: handle collapsed functions # TODO: handle collapsed functions
#assert last_name == name #assert last_name == name
continue continue
self.symbols.append((addr, name)) self.symbols.append((addr, name))
last_addr = addr last_addr = addr
last_name = name last_name = name
# sort symbols # sort symbols
self.symbols.sort(key = lambda (addr, name): addr) self.symbols.sort(key = lambda (addr, name): addr)
def lookup_addr(self, addr): def lookup_addr(self, addr):
try: try:
return self.symbol_cache[addr] return self.symbol_cache[addr]
except KeyError: except KeyError:
pass pass
tolerance = 4196 tolerance = 4196
s, e = 0, len(self.symbols) s, e = 0, len(self.symbols)
while s != e: while s != e:
i = (s + e)//2 i = (s + e)//2
start_addr, name = self.symbols[i] start_addr, name = self.symbols[i]
try: try:
end_addr, next_name = self.symbols[i + 1] end_addr, next_name = self.symbols[i + 1]
except IndexError: except IndexError:
end_addr = start_addr + tolerance end_addr = start_addr + tolerance
if addr < start_addr: if addr < start_addr:
e = i e = i
continue continue
if addr == end_addr: if addr == end_addr:
return next_name return next_name
if addr > end_addr: if addr > end_addr:
s = i s = i
continue continue
return name return name
return "0x%08x" % addr return "0x%08x" % addr
def lookup_symbol(self, name): def lookup_symbol(self, name):
for symbol_addr, symbol_name in self.symbols: for symbol_addr, symbol_name in self.symbols:
if name == symbol_name: if name == symbol_name:
return symbol_addr return symbol_addr
return 0 return 0
def read_data(self, data): def read_data(self, data):
# TODO: compute these automatically # TODO: compute these automatically
caller_overhead = 672 - 2*144 # __debug_profile_reference2 - 2*__debug_profile_reference1 caller_overhead = 672 - 2*144 # __debug_profile_reference2 - 2*__debug_profile_reference1
callee_overhead = 144 # __debug_profile_reference1 callee_overhead = 144 # __debug_profile_reference1
callee_overhead -= 48 # tolerance callee_overhead -= 48 # tolerance
caller_overhead = callee_overhead caller_overhead = callee_overhead
fp = file(data, "rb") fp = file(data, "rb")
entry_format = "II" entry_format = "II"
entry_size = struct.calcsize(entry_format) entry_size = struct.calcsize(entry_format)
stack = [] stack = []
last_stamp = 0 last_stamp = 0
delta = 0 delta = 0
while True: while True:
entry = fp.read(entry_size) entry = fp.read(entry_size)
if len(entry) < entry_size: if len(entry) < entry_size:
break break
addr_exit, stamp = struct.unpack(entry_format, entry) addr_exit, stamp = struct.unpack(entry_format, entry)
if addr_exit == 0 and stamp == 0: if addr_exit == 0 and stamp == 0:
break break
addr = addr_exit & 0xfffffffe addr = addr_exit & 0xfffffffe
exit = addr_exit & 0x00000001 exit = addr_exit & 0x00000001
if self.base_addr is None: if self.base_addr is None:
ref_addr = self.lookup_symbol('__debug_profile_reference2') ref_addr = self.lookup_symbol('__debug_profile_reference2')
if ref_addr: if ref_addr:
self.base_addr = (addr - ref_addr) & ~(options.align - 1) self.base_addr = (addr - ref_addr) & ~(options.align - 1)
else: else:
self.base_addr = 0 self.base_addr = 0
#print hex(self.base_addr) #print hex(self.base_addr)
rel_addr = addr - self.base_addr rel_addr = addr - self.base_addr
#print hex(addr - self.base_addr) #print hex(addr - self.base_addr)
name = self.lookup_addr(rel_addr) name = self.lookup_addr(rel_addr)
stamp = self.unwrap_stamp(stamp) stamp = self.unwrap_stamp(stamp)
delta += stamp - last_stamp delta += stamp - last_stamp
if not exit: if not exit:
if options.verbose >= 2: if options.verbose >= 2:
print "%10u >> 0x%08x" % (stamp, addr) print "%10u >> 0x%08x" % (stamp, addr)
if options.verbose: if options.verbose:
print "%10u >> %s" % (stamp, name) print "%10u >> %s" % (stamp, name)
delta -= caller_overhead delta -= caller_overhead
stack.append((name, stamp, delta)) stack.append((name, stamp, delta))
delta = 0 delta = 0
else: else:
if options.verbose >= 2: if options.verbose >= 2:
print "%10u << 0x%08x" % (stamp, addr) print "%10u << 0x%08x" % (stamp, addr)
if len(stack): if len(stack):
self_time = delta - callee_overhead self_time = delta - callee_overhead
entry_name, entry_stamp, delta = stack.pop() entry_name, entry_stamp, delta = stack.pop()
if entry_name != name: if entry_name != name:
if options.verbose: if options.verbose:
print "%10u << %s" % (stamp, name) print "%10u << %s" % (stamp, name)
#assert entry_name == name #assert entry_name == name
break break
total_time = stamp - entry_stamp total_time = stamp - entry_stamp
self.functions[entry_name] = self.functions.get(entry_name, 0) + self_time self.functions[entry_name] = self.functions.get(entry_name, 0) + self_time
if options.verbose: if options.verbose:
print "%10u << %s %+u" % (stamp, name, self_time) print "%10u << %s %+u" % (stamp, name, self_time)
else: else:
delta = 0 delta = 0
last_stamp = stamp last_stamp = stamp
def write_report(self): def write_report(self):
total = sum(self.functions.values()) total = sum(self.functions.values())
results = self.functions.items() results = self.functions.items()
results.sort(key = lambda (name, time): -time) results.sort(key = lambda (name, time): -time)
for name, time in results: for name, time in results:
perc = float(time)/float(total)*100.0 perc = float(time)/float(total)*100.0
print "%6.03f %s" % (perc, name) print "%6.03f %s" % (perc, name)
def main(): def main():
parser = optparse.OptionParser( parser = optparse.OptionParser(
usage="\n\t%prog [options] [file] ...", usage="\n\t%prog [options] [file] ...",
version="%%prog %s" % __version__) version="%%prog %s" % __version__)
parser.add_option( parser.add_option(
'-a', '--align', metavar='NUMBER', '-a', '--align', metavar='NUMBER',
type="int", dest="align", default=16, type="int", dest="align", default=16,
help="section alignment") help="section alignment")
parser.add_option( parser.add_option(
'-m', '--map', metavar='FILE', '-m', '--map', metavar='FILE',
type="string", dest="map", type="string", dest="map",
help="map file") help="map file")
parser.add_option( parser.add_option(
'-b', '--base', metavar='FILE', '-b', '--base', metavar='FILE',
type="string", dest="base", type="string", dest="base",
help="base addr") help="base addr")
parser.add_option( parser.add_option(
'-v', '--verbose', '-v', '--verbose',
action="count", action="count",
dest="verbose", default=0, dest="verbose", default=0,
help="verbose output") help="verbose output")
global options global options
(options, args) = parser.parse_args(sys.argv[1:]) (options, args) = parser.parse_args(sys.argv[1:])
profile = Profile() profile = Profile()
if options.base is not None: if options.base is not None:
profile.base_addr = int(options.base, 16) profile.base_addr = int(options.base, 16)
if options.map is not None: if options.map is not None:
profile.read_map(options.map) profile.read_map(options.map)
for arg in args: for arg in args:
profile.read_data(arg) profile.read_data(arg)
profile.write_report() profile.write_report()
if __name__ == '__main__': if __name__ == '__main__':
main() main()