diff --git a/scripts/code.py b/scripts/code.py index aa93b8b3..f49c6890 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -158,6 +158,21 @@ def openio(path, mode='r', buffering=-1): else: return open(path, mode, buffering) +class Sym(co.namedtuple('Sym', [ + 'name', 'global_', 'section', 'addr', 'size'])): + __slots__ = () + def __new__(cls, name, global_, section, addr, size): + return super().__new__(cls, name, global_, section, addr, size) + + def __repr__(self): + return '%s(%r, %r, %r, 0x%x, 0x%x)' % ( + self.__class__.__name__, + self.name, + self.global_, + self.section, + self.addr, + self.size) + class SymInfo: def __init__(self, syms): self.syms = syms @@ -168,12 +183,13 @@ class SymInfo: # organize by symbol, note multiple symbols can share a name if not hasattr(self, '_by_sym'): by_sym = {} - for sym, addr, size in self.syms: - if sym not in by_sym: - by_sym[sym] = [] - if (addr, size) not in by_sym[sym]: - by_sym[sym].append((addr, size)) + for sym in self.syms: + if sym.name not in by_sym: + by_sym[sym.name] = [] + if sym not in by_sym[sym.name]: + by_sym[sym.name].append(sym) self._by_sym = by_sym + return self._by_sym.get(k, d) else: @@ -183,21 +199,21 @@ class SymInfo: if not hasattr(self, '_by_addr'): # sort and keep largest/first when duplicates syms = self.syms.copy() - syms.sort(key=lambda x: (x[1], -x[2], x[0])) + syms.sort(key=lambda x: (x.addr, -x.size)) by_addr = [] - for name, addr, size in syms: + for sym in syms: if (len(by_addr) == 0 - or by_addr[-1][0] != addr): - by_addr.append((name, addr, size)) + or by_addr[-1].addr != sym.addr): + by_addr.append(sym) self._by_addr = by_addr # find sym by range i = bisect.bisect(self._by_addr, k, - key=lambda x: x[1]) + key=lambda x: x.addr) # check that we're actually in this sym's size - if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]: - return self._by_addr[i-1][0] + if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size: + return self._by_addr[i-1] else: return d @@ -216,7 +232,16 @@ class SymInfo: def __iter__(self): return iter(self.syms) -def collect_syms(obj_path, sections=None, global_=False, *, + def globals(self): + return SymInfo([sym for sym in self.syms + if sym.global_]) + + def section(self, section): + return SymInfo([sym for sym in self.syms + # note we accept prefixes + if s.startswith(section)]) + +def collect_syms(obj_path, global_=False, sections=None, *, objdump_path=OBJDUMP_PATH, **args): symbol_pattern = re.compile( @@ -250,7 +275,8 @@ def collect_syms(obj_path, sections=None, global_=False, *, # u => unique global # => neither # ! => local + global - if global_ and scope in 'l ': + global__ = scope not in 'l ' + if global_ and not global__: continue # filter by section? note we accept prefixes if (sections is not None @@ -261,7 +287,7 @@ def collect_syms(obj_path, sections=None, global_=False, *, if not size: continue # note multiple symbols can share a name - syms.append((name, addr, size)) + syms.append(Sym(name, global__, section, addr, size)) proc.wait() if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) @@ -487,14 +513,14 @@ def collect(obj_paths, *, **args) # map function sizes to debug symbols - for sym, _, size in syms: + for sym in syms: # discard internal functions - if not everything and sym.startswith('__'): + if not everything and sym.name.startswith('__'): continue # find best matching dwarf entry, this may be slightly different # due to optimizations - entry = info.get(sym) + entry = info.get(sym.name) # if we have no file guess from obj path if entry is not None and 'DW_AT_decl_file' in entry: @@ -514,7 +540,7 @@ def collect(obj_paths, *, os.path.abspath(file)]) == os.getcwd(): continue - results.append(CodeResult(file, sym, size)) + results.append(CodeResult(file, sym.name, sym.size)) return results diff --git a/scripts/ctx.py b/scripts/ctx.py index b18d4d0e..5e911d40 100755 --- a/scripts/ctx.py +++ b/scripts/ctx.py @@ -167,6 +167,21 @@ def openio(path, mode='r', buffering=-1): else: return open(path, mode, buffering) +class Sym(co.namedtuple('Sym', [ + 'name', 'global_', 'section', 'addr', 'size'])): + __slots__ = () + def __new__(cls, name, global_, section, addr, size): + return super().__new__(cls, name, global_, section, addr, size) + + def __repr__(self): + return '%s(%r, %r, %r, 0x%x, 0x%x)' % ( + self.__class__.__name__, + self.name, + self.global_, + self.section, + self.addr, + self.size) + class SymInfo: def __init__(self, syms): self.syms = syms @@ -177,12 +192,13 @@ class SymInfo: # organize by symbol, note multiple symbols can share a name if not hasattr(self, '_by_sym'): by_sym = {} - for sym, addr, size in self.syms: - if sym not in by_sym: - by_sym[sym] = [] - if (addr, size) not in by_sym[sym]: - by_sym[sym].append((addr, size)) + for sym in self.syms: + if sym.name not in by_sym: + by_sym[sym.name] = [] + if sym not in by_sym[sym.name]: + by_sym[sym.name].append(sym) self._by_sym = by_sym + return self._by_sym.get(k, d) else: @@ -192,21 +208,21 @@ class SymInfo: if not hasattr(self, '_by_addr'): # sort and keep largest/first when duplicates syms = self.syms.copy() - syms.sort(key=lambda x: (x[1], -x[2], x[0])) + syms.sort(key=lambda x: (x.addr, -x.size)) by_addr = [] - for name, addr, size in syms: + for sym in syms: if (len(by_addr) == 0 - or by_addr[-1][0] != addr): - by_addr.append((name, addr, size)) + or by_addr[-1].addr != sym.addr): + by_addr.append(sym) self._by_addr = by_addr # find sym by range i = bisect.bisect(self._by_addr, k, - key=lambda x: x[1]) + key=lambda x: x.addr) # check that we're actually in this sym's size - if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]: - return self._by_addr[i-1][0] + if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size: + return self._by_addr[i-1] else: return d @@ -225,7 +241,16 @@ class SymInfo: def __iter__(self): return iter(self.syms) -def collect_syms(obj_path, sections=None, global_=False, *, + def globals(self): + return SymInfo([sym for sym in self.syms + if sym.global_]) + + def section(self, section): + return SymInfo([sym for sym in self.syms + # note we accept prefixes + if s.startswith(section)]) + +def collect_syms(obj_path, global_=False, sections=None, *, objdump_path=OBJDUMP_PATH, **args): symbol_pattern = re.compile( @@ -259,7 +284,8 @@ def collect_syms(obj_path, sections=None, global_=False, *, # u => unique global # => neither # ! => local + global - if global_ and scope in 'l ': + global__ = scope not in 'l ' + if global_ and not global__: continue # filter by section? note we accept prefixes if (sections is not None @@ -270,7 +296,7 @@ def collect_syms(obj_path, sections=None, global_=False, *, if not size: continue # note multiple symbols can share a name - syms.append((name, addr, size)) + syms.append(Sym(name, global__, section, addr, size)) proc.wait() if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) @@ -649,13 +675,13 @@ def collect(obj_paths, *, return children, notes # find each function's context - for sym, _, _ in syms: + for sym in syms: # discard internal functions - if not everything and sym.startswith('__'): + if not everything and sym.name.startswith('__'): continue # find best matching dwarf entry - entry = info.get(sym) + entry = info.get(sym.name) # skip non-functions if entry is None or entry.tag != 'DW_TAG_subprogram': diff --git a/scripts/data.py b/scripts/data.py index 54f9d65b..89839b85 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -158,6 +158,21 @@ def openio(path, mode='r', buffering=-1): else: return open(path, mode, buffering) +class Sym(co.namedtuple('Sym', [ + 'name', 'global_', 'section', 'addr', 'size'])): + __slots__ = () + def __new__(cls, name, global_, section, addr, size): + return super().__new__(cls, name, global_, section, addr, size) + + def __repr__(self): + return '%s(%r, %r, %r, 0x%x, 0x%x)' % ( + self.__class__.__name__, + self.name, + self.global_, + self.section, + self.addr, + self.size) + class SymInfo: def __init__(self, syms): self.syms = syms @@ -168,12 +183,13 @@ class SymInfo: # organize by symbol, note multiple symbols can share a name if not hasattr(self, '_by_sym'): by_sym = {} - for sym, addr, size in self.syms: - if sym not in by_sym: - by_sym[sym] = [] - if (addr, size) not in by_sym[sym]: - by_sym[sym].append((addr, size)) + for sym in self.syms: + if sym.name not in by_sym: + by_sym[sym.name] = [] + if sym not in by_sym[sym.name]: + by_sym[sym.name].append(sym) self._by_sym = by_sym + return self._by_sym.get(k, d) else: @@ -183,21 +199,21 @@ class SymInfo: if not hasattr(self, '_by_addr'): # sort and keep largest/first when duplicates syms = self.syms.copy() - syms.sort(key=lambda x: (x[1], -x[2], x[0])) + syms.sort(key=lambda x: (x.addr, -x.size)) by_addr = [] - for name, addr, size in syms: + for sym in syms: if (len(by_addr) == 0 - or by_addr[-1][0] != addr): - by_addr.append((name, addr, size)) + or by_addr[-1].addr != sym.addr): + by_addr.append(sym) self._by_addr = by_addr # find sym by range i = bisect.bisect(self._by_addr, k, - key=lambda x: x[1]) + key=lambda x: x.addr) # check that we're actually in this sym's size - if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]: - return self._by_addr[i-1][0] + if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size: + return self._by_addr[i-1] else: return d @@ -216,7 +232,16 @@ class SymInfo: def __iter__(self): return iter(self.syms) -def collect_syms(obj_path, sections=None, global_=False, *, + def globals(self): + return SymInfo([sym for sym in self.syms + if sym.global_]) + + def section(self, section): + return SymInfo([sym for sym in self.syms + # note we accept prefixes + if s.startswith(section)]) + +def collect_syms(obj_path, global_=False, sections=None, *, objdump_path=OBJDUMP_PATH, **args): symbol_pattern = re.compile( @@ -250,7 +275,8 @@ def collect_syms(obj_path, sections=None, global_=False, *, # u => unique global # => neither # ! => local + global - if global_ and scope in 'l ': + global__ = scope not in 'l ' + if global_ and not global__: continue # filter by section? note we accept prefixes if (sections is not None @@ -261,7 +287,7 @@ def collect_syms(obj_path, sections=None, global_=False, *, if not size: continue # note multiple symbols can share a name - syms.append((name, addr, size)) + syms.append(Sym(name, global__, section, addr, size)) proc.wait() if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) @@ -487,14 +513,14 @@ def collect(obj_paths, *, **args) # map function sizes to debug symbols - for sym, _, size in syms: + for sym in syms: # discard internal functions - if not everything and sym.startswith('__'): + if not everything and sym.name.startswith('__'): continue # find best matching dwarf entry, this may be slightly different # due to optimizations - entry = info.get(sym) + entry = info.get(sym.name) # if we have no file guess from obj path if entry is not None and 'DW_AT_decl_file' in entry: @@ -514,7 +540,7 @@ def collect(obj_paths, *, os.path.abspath(file)]) == os.getcwd(): continue - results.append(DataResult(file, sym, size)) + results.append(DataResult(file, sym.name, sym.size)) return results diff --git a/scripts/perf.py b/scripts/perf.py index fe53cdcc..a8874884 100755 --- a/scripts/perf.py +++ b/scripts/perf.py @@ -260,6 +260,21 @@ def multiprocessing_cache(f): return multiprocessing_cache +class Sym(co.namedtuple('Sym', [ + 'name', 'global_', 'section', 'addr', 'size'])): + __slots__ = () + def __new__(cls, name, global_, section, addr, size): + return super().__new__(cls, name, global_, section, addr, size) + + def __repr__(self): + return '%s(%r, %r, %r, 0x%x, 0x%x)' % ( + self.__class__.__name__, + self.name, + self.global_, + self.section, + self.addr, + self.size) + class SymInfo: def __init__(self, syms): self.syms = syms @@ -270,12 +285,13 @@ class SymInfo: # organize by symbol, note multiple symbols can share a name if not hasattr(self, '_by_sym'): by_sym = {} - for sym, addr, size in self.syms: - if sym not in by_sym: - by_sym[sym] = [] - if (addr, size) not in by_sym[sym]: - by_sym[sym].append((addr, size)) + for sym in self.syms: + if sym.name not in by_sym: + by_sym[sym.name] = [] + if sym not in by_sym[sym.name]: + by_sym[sym.name].append(sym) self._by_sym = by_sym + return self._by_sym.get(k, d) else: @@ -285,21 +301,21 @@ class SymInfo: if not hasattr(self, '_by_addr'): # sort and keep largest/first when duplicates syms = self.syms.copy() - syms.sort(key=lambda x: (x[1], -x[2], x[0])) + syms.sort(key=lambda x: (x.addr, -x.size)) by_addr = [] - for name, addr, size in syms: + for sym in syms: if (len(by_addr) == 0 - or by_addr[-1][0] != addr): - by_addr.append((name, addr, size)) + or by_addr[-1].addr != sym.addr): + by_addr.append(sym) self._by_addr = by_addr # find sym by range i = bisect.bisect(self._by_addr, k, - key=lambda x: x[1]) + key=lambda x: x.addr) # check that we're actually in this sym's size - if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]: - return self._by_addr[i-1][0] + if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size: + return self._by_addr[i-1] else: return d @@ -318,8 +334,17 @@ class SymInfo: def __iter__(self): return iter(self.syms) + def globals(self): + return SymInfo([sym for sym in self.syms + if sym.global_]) + + def section(self, section): + return SymInfo([sym for sym in self.syms + # note we accept prefixes + if s.startswith(section)]) + @multiprocessing_cache -def collect_syms(obj_path, sections=None, global_=False, *, +def collect_syms(obj_path, global_=False, sections=None, *, objdump_path=OBJDUMP_PATH, **args): symbol_pattern = re.compile( @@ -353,7 +378,8 @@ def collect_syms(obj_path, sections=None, global_=False, *, # u => unique global # => neither # ! => local + global - if global_ and scope in 'l ': + global__ = scope not in 'l ' + if global_ and not global__: continue # filter by section? note we accept prefixes if (sections is not None @@ -364,7 +390,7 @@ def collect_syms(obj_path, sections=None, global_=False, *, if not size: continue # note multiple symbols can share a name - syms.append((name, addr, size)) + syms.append(Sym(name, global__, section, addr, size)) proc.wait() if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) @@ -633,16 +659,16 @@ def collect_decompressed(path, *, sym_addr_ = addr_ - off # track possible deltas? - for sym_addr, size in syms[sym]: - delta = sym_addr - sym_addr_ + for sym_ in syms[sym]: + delta = sym_.addr - sym_addr_ if delta not in deltas[dso]: deltas[dso][delta] = sum( abs(a_+delta - a) for s, (a_, _) in syms_[dso].items() for a, _ in syms[s]) for delta in deltas[dso].keys(): - deltas[dso][delta] += abs(sym_addr_+delta - sym_addr) - syms_[dso][sym] = sym_addr_, size + deltas[dso][delta] += abs(sym_addr_+delta - sym_.addr) + syms_[dso][sym] = sym_addr_, sym_.size # guess the best delta delta, _ = min(deltas[dso].items(), diff --git a/scripts/perfbd.py b/scripts/perfbd.py index 1c659b89..ab691085 100755 --- a/scripts/perfbd.py +++ b/scripts/perfbd.py @@ -167,6 +167,21 @@ def openio(path, mode='r', buffering=-1): else: return open(path, mode, buffering) +class Sym(co.namedtuple('Sym', [ + 'name', 'global_', 'section', 'addr', 'size'])): + __slots__ = () + def __new__(cls, name, global_, section, addr, size): + return super().__new__(cls, name, global_, section, addr, size) + + def __repr__(self): + return '%s(%r, %r, %r, 0x%x, 0x%x)' % ( + self.__class__.__name__, + self.name, + self.global_, + self.section, + self.addr, + self.size) + class SymInfo: def __init__(self, syms): self.syms = syms @@ -177,12 +192,13 @@ class SymInfo: # organize by symbol, note multiple symbols can share a name if not hasattr(self, '_by_sym'): by_sym = {} - for sym, addr, size in self.syms: - if sym not in by_sym: - by_sym[sym] = [] - if (addr, size) not in by_sym[sym]: - by_sym[sym].append((addr, size)) + for sym in self.syms: + if sym.name not in by_sym: + by_sym[sym.name] = [] + if sym not in by_sym[sym.name]: + by_sym[sym.name].append(sym) self._by_sym = by_sym + return self._by_sym.get(k, d) else: @@ -192,21 +208,21 @@ class SymInfo: if not hasattr(self, '_by_addr'): # sort and keep largest/first when duplicates syms = self.syms.copy() - syms.sort(key=lambda x: (x[1], -x[2], x[0])) + syms.sort(key=lambda x: (x.addr, -x.size)) by_addr = [] - for name, addr, size in syms: + for sym in syms: if (len(by_addr) == 0 - or by_addr[-1][0] != addr): - by_addr.append((name, addr, size)) + or by_addr[-1].addr != sym.addr): + by_addr.append(sym) self._by_addr = by_addr # find sym by range i = bisect.bisect(self._by_addr, k, - key=lambda x: x[1]) + key=lambda x: x.addr) # check that we're actually in this sym's size - if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]: - return self._by_addr[i-1][0] + if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size: + return self._by_addr[i-1] else: return d @@ -225,7 +241,16 @@ class SymInfo: def __iter__(self): return iter(self.syms) -def collect_syms(obj_path, sections=None, global_=False, *, + def globals(self): + return SymInfo([sym for sym in self.syms + if sym.global_]) + + def section(self, section): + return SymInfo([sym for sym in self.syms + # note we accept prefixes + if s.startswith(section)]) + +def collect_syms(obj_path, global_=False, sections=None, *, objdump_path=OBJDUMP_PATH, **args): symbol_pattern = re.compile( @@ -259,7 +284,8 @@ def collect_syms(obj_path, sections=None, global_=False, *, # u => unique global # => neither # ! => local + global - if global_ and scope in 'l ': + global__ = scope not in 'l ' + if global_ and not global__: continue # filter by section? note we accept prefixes if (sections is not None @@ -270,7 +296,7 @@ def collect_syms(obj_path, sections=None, global_=False, *, if not size: continue # note multiple symbols can share a name - syms.append((name, addr, size)) + syms.append(Sym(name, global__, section, addr, size)) proc.wait() if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) @@ -601,7 +627,9 @@ def collect_job(path, start, stop, syms, lines, *, else: # find sym sym = syms.get(addr) - if sym is None: + if sym is not None: + sym = sym.name + else: sym = hex(addr) # filter out internal/unknown functions