From 8526cd9cf1f6ffc883fd7a05d53e445bd0b839d2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 2 Dec 2024 19:23:42 -0600 Subject: [PATCH] scripts: Prevented i/children/notes result field collisions Without this, naming a column i/children/notes in csv.py could cause things to break. Unlikely for children/notes, but very likely for i, especially when benchmarking. Unfortunately namedtuple makes this tricky. I _want_ to just rename these to _i/_children/_notes and call the problem solved, but namedtuple reserves all underscore-prefixed fields for its own use. As a workaround, the table renderer now looks for _i/_children/_notes at the _class_ level, as an optional name of which namedtuple field to use. This way Result types can stay lightweight namedtuples while including extra table rendering info without risk of conflicts. This also makes the HotResult type a bit more funky, but that's not a big deal. --- scripts/code.py | 59 +++++++++++++++++++++++-------------------- scripts/cov.py | 59 +++++++++++++++++++++++-------------------- scripts/csv.py | 59 +++++++++++++++++++++++-------------------- scripts/ctx.py | 62 ++++++++++++++++++++++++++-------------------- scripts/data.py | 59 +++++++++++++++++++++++-------------------- scripts/perf.py | 60 ++++++++++++++++++++++++-------------------- scripts/perfbd.py | 60 ++++++++++++++++++++++++-------------------- scripts/stack.py | 60 ++++++++++++++++++++++++-------------------- scripts/structs.py | 61 +++++++++++++++++++++++++-------------------- 9 files changed, 296 insertions(+), 243 deletions(-) diff --git a/scripts/code.py b/scripts/code.py index 43ae73de..b08439ff 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -509,29 +509,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -555,20 +558,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -710,8 +713,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -725,7 +728,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -759,7 +764,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -779,7 +784,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/cov.py b/scripts/cov.py index fb62ba97..11e3f54b 100755 --- a/scripts/cov.py +++ b/scripts/cov.py @@ -413,29 +413,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -459,20 +462,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -614,8 +617,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -629,7 +632,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -663,7 +668,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -683,7 +688,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/csv.py b/scripts/csv.py index c45d0042..82f5a7f9 100755 --- a/scripts/csv.py +++ b/scripts/csv.py @@ -1425,29 +1425,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -1471,20 +1474,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -1626,8 +1629,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -1641,7 +1644,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -1675,7 +1680,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -1695,7 +1700,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/ctx.py b/scripts/ctx.py index 80fb0866..2f8a241c 100755 --- a/scripts/ctx.py +++ b/scripts/ctx.py @@ -134,6 +134,9 @@ class CtxResult(co.namedtuple('CtxResult', [ _fields = ['size'] _sort = ['size'] _types = {'size': RInt} + _i = 'i' + _children = 'children' + _notes = 'notes' __slots__ = () def __new__(cls, file='', function='', size=0, @@ -739,29 +742,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -785,20 +791,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -940,8 +946,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -955,7 +961,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -989,7 +997,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -1009,7 +1017,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/data.py b/scripts/data.py index 7b73be09..eae65a27 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -509,29 +509,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -555,20 +558,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -710,8 +713,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -725,7 +728,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -759,7 +764,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -779,7 +784,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/perf.py b/scripts/perf.py index 8b20a1f0..22dfd542 100755 --- a/scripts/perf.py +++ b/scripts/perf.py @@ -151,6 +151,7 @@ class PerfResult(co.namedtuple('PerfResult', [ 'cycles': RInt, 'bmisses': RInt, 'branches': RInt, 'cmisses': RInt, 'caches': RInt} + _children = 'children' __slots__ = () def __new__(cls, file='', function='', line=0, @@ -815,29 +816,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -861,20 +865,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -1016,8 +1020,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -1031,7 +1035,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -1065,7 +1071,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -1085,7 +1091,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/perfbd.py b/scripts/perfbd.py index 18d7817d..aba62fca 100755 --- a/scripts/perfbd.py +++ b/scripts/perfbd.py @@ -139,6 +139,7 @@ class PerfBdResult(co.namedtuple('PerfBdResult', [ _fields = ['readed', 'proged', 'erased'] _sort = ['erased', 'proged', 'readed'] _types = {'readed': RInt, 'proged': RInt, 'erased': RInt} + _children = 'children' __slots__ = () def __new__(cls, file='', function='', line=0, @@ -778,29 +779,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -824,20 +828,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -979,8 +983,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -994,7 +998,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -1028,7 +1034,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -1048,7 +1054,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/stack.py b/scripts/stack.py index d336bd18..ee8d074b 100755 --- a/scripts/stack.py +++ b/scripts/stack.py @@ -127,6 +127,7 @@ class StackResult(co.namedtuple('StackResult', [ _fields = ['frame', 'limit'] _sort = ['limit', 'frame'] _types = {'frame': RInt, 'limit': RInt} + _children = 'children' __slots__ = () def __new__(cls, file='', function='', frame=0, limit=0, @@ -361,29 +362,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -407,20 +411,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -562,8 +566,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -577,7 +581,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -611,7 +617,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -631,7 +637,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ", diff --git a/scripts/structs.py b/scripts/structs.py index ffc8b17e..a2e7a20b 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -134,6 +134,8 @@ class StructResult(co.namedtuple('StructResult', [ _fields = ['size', 'align'] _sort = ['size', 'align'] _types = {'size': RInt, 'align': RInt} + _i = 'i' + _children = 'children' __slots__ = () def __new__(cls, file='', struct='', size=0, align=0, @@ -604,29 +606,32 @@ def table(Result, results, diff_results=None, *, # reduce children to hot paths? only used by some scripts if hot: # subclass to reintroduce __dict__ - class HotResult(Result): - i = None - children = None - notes = None + Result_ = Result + class HotResult(Result_): + _i = '_hot_i' + _children = '_hot_children' + _notes = '_hot_notes' + def __new__(cls, r, i=None, children=None, notes=None): self = HotResult._make(r) - self.i = i - self.children = children if children is not None else [] - self.notes = notes if notes is not None else [] - if hasattr(r, 'notes'): - self.notes.extend(r.notes) + self._hot_i = i + self._hot_children = children if children is not None else [] + self._hot_notes = notes if notes is not None else [] + if hasattr(Result_, '_notes'): + self._hot_notes.extend(getattr(r, r._notes)) return self def __add__(self, other): return HotResult( - Result.__add__(self, other), - self.i if other.i is None - else other.i if self.i is None - else min(self.i, other.i), - self.children + other.children, - self.notes + other.notes) + Result_.__add__(self, other), + self._hot_i if other._hot_i is None + else other._hot_i if self._hot_i is None + else min(self._hot_i, other._hot_i), + self._hot_children + other._hot_children, + self._hot_notes + other._hot_notes) - def hot_(results_, depth_): + results_ = [] + for r in results: hot_ = [] def recurse(results_, depth_, seen=set()): nonlocal hot_ @@ -650,20 +655,20 @@ def table(Result, results, diff_results=None, *, # found a cycle? if (detect_cycles and tuple(getattr(r, k) for k in Result._by) in seen): - hot_[-1].notes.append('cycle detected') + hot_[-1]._hot_notes.append('cycle detected') return # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {tuple(getattr(r, k) for k in Result._by)}) - recurse(results_, depth_) - return hot_ + recurse(getattr(r, Result._children), depth-1) + results_.append(HotResult(r, children=hot_)) - results = [r._replace(children=hot_(r.children, depth-1)) - for r in results] + Result = HotResult + results = results_ # organize by name table = { @@ -805,8 +810,8 @@ def table(Result, results, diff_results=None, *, getattr(r, k, None), getattr(diff_r, k, None))))) # append any notes - if hasattr(r, 'notes'): - entry[-1][1].extend(r.notes) + if hasattr(Result, '_notes'): + entry[-1][1].extend(getattr(r, Result._notes)) return entry # recursive entry helper, only used by some scripts @@ -820,7 +825,9 @@ def table(Result, results, diff_results=None, *, names_ = list(table_.keys()) # sort the children layer - names_.sort(key=lambda n: (getattr(table_[n], 'i', None), n)) + names_.sort() + if hasattr(Result, '_i'): + names_.sort(key=lambda n: getattr(table_[n], Result._i)) if sort: for k, reverse in reversed(sort): names_.sort( @@ -854,7 +861,7 @@ def table(Result, results, diff_results=None, *, # recurse? if depth_ > 1: - recurse(r.children, + recurse(getattr(r, Result._children), depth_-1, seen | {name}, (prefixes[2+is_last] + "|-> ", @@ -874,7 +881,7 @@ def table(Result, results, diff_results=None, *, # recursive entries if name in table and depth > 1: - recurse(table[name].children, + recurse(getattr(table[name], Result._children), depth-1, {name}, ("|-> ",