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