diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/win32kprof.py | 482 |
1 files changed, 241 insertions, 241 deletions
diff --git a/bin/win32kprof.py b/bin/win32kprof.py index 1876fbc067..c1aabc48c9 100755 --- a/bin/win32kprof.py +++ b/bin/win32kprof.py @@ -37,262 +37,262 @@ __version__ = '0.1' class ParseError(Exception): - pass + pass class MsvcDemangler: - # http://www.kegel.com/mangle.html - - def __init__(self, symbol): - self._symbol = symbol - self._pos = 0 - - 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 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_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 + # http://www.kegel.com/mangle.html + + def __init__(self, symbol): + self._symbol = symbol + self._pos = 0 + + 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 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_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 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 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) - - 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 - - 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 - - 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) - - name = self.lookup_addr(rel_addr) - stamp = self.unwrap_stamp(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 - - 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 __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 + + # sort symbols + self.symbols.sort(key = lambda (addr, name): addr) + + 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 + + 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 + + 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) + + name = self.lookup_addr(rel_addr) + stamp = self.unwrap_stamp(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 + + 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 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") - - 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() + 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:]) + + 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() |