forked from Imagelibrary/littlefs
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.
This commit is contained in:
@@ -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},
|
||||
("|-> ",
|
||||
|
||||
Reference in New Issue
Block a user