scripts: Added -t/--hot to recursive scripts, stack.py, etc
This is mainly useful for stack.py, where -t/--hot lets you quickly see everything that contributes to the stack limit for each function. This was (and still is) possible with -s + -z, but it was pretty annoying to use: - The stack trace rendered _diagonally_ as a consequence of -z, which is probably the worst use of screen real estate. - This trick only really worked with -s, which was the opposite order of what you usually want on the command line: -S. Adding a special for-purpose -t/--hot flag makes looking at the hot path much easier, at the cost of more hacky python code (and I _mean_ hacky, making the hot path selection useful while following exising sort rules was annoyingly complicated). Also added -t/--hot to perf.py and perfbd.py for consistency, though it makes a bit less sense there. Also also reworked related code in all three scripts: stack.py, perf.py, perfbd.py. The logic should be a bit more equivalent, and perf.py/perfbd.py detect cycles now.
This commit is contained in:
+95
-15
@@ -675,7 +675,8 @@ def table(Result, results, diff_results=None, *,
|
|||||||
summary=False,
|
summary=False,
|
||||||
all=False,
|
all=False,
|
||||||
percent=False,
|
percent=False,
|
||||||
depth=1,
|
depth=None,
|
||||||
|
hot=False,
|
||||||
**_):
|
**_):
|
||||||
all_, all = all, __builtins__.all
|
all_, all = all, __builtins__.all
|
||||||
|
|
||||||
@@ -830,24 +831,25 @@ def table(Result, results, diff_results=None, *,
|
|||||||
|
|
||||||
if not summary:
|
if not summary:
|
||||||
# find the actual depth
|
# find the actual depth
|
||||||
#
|
|
||||||
# note unlike stack.py we can't end up with cycles here
|
|
||||||
depth_ = depth
|
depth_ = depth
|
||||||
if m.isinf(depth_):
|
if hot:
|
||||||
def rec_depth(results_):
|
depth_ = 2
|
||||||
|
elif m.isinf(depth_):
|
||||||
|
def rec_depth(results_, seen=set()):
|
||||||
# rebuild our tables at each layer
|
# rebuild our tables at each layer
|
||||||
table_ = {
|
table_ = {
|
||||||
','.join(str(getattr(r, k) or '') for k in by): r
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
for r in results_}
|
for r in results_}
|
||||||
names_ = list(table_.keys())
|
names_ = list(table_.keys())
|
||||||
|
|
||||||
return max((
|
return max(
|
||||||
rec_depth(table_[name].children)
|
(rec_depth(table_[name].children, seen | {name})
|
||||||
for name in names_),
|
for name in names_
|
||||||
|
if name not in seen),
|
||||||
default=-1) + 1
|
default=-1) + 1
|
||||||
|
|
||||||
depth_ = max((
|
depth_ = max(
|
||||||
rec_depth(table[name].children)
|
(rec_depth(table[name].children, {name})
|
||||||
for name in names
|
for name in names
|
||||||
if name in table),
|
if name in table),
|
||||||
default=-1) + 1
|
default=-1) + 1
|
||||||
@@ -864,7 +866,67 @@ def table(Result, results, diff_results=None, *,
|
|||||||
for i, x in enumerate(lines[0][1:], 1))))
|
for i, x in enumerate(lines[0][1:], 1))))
|
||||||
|
|
||||||
if not summary:
|
if not summary:
|
||||||
def recurse(results_, depth_, prefixes=('', '', '', '')):
|
if hot:
|
||||||
|
def recurse(results_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
|
# rebuild our tables at each layer
|
||||||
|
table_ = {
|
||||||
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
|
for r in results_}
|
||||||
|
names_ = list(table_.keys())
|
||||||
|
if not names_:
|
||||||
|
return
|
||||||
|
|
||||||
|
# find the "hottest" path at each step, we use
|
||||||
|
# the sort field if requested, but ignore reversedness
|
||||||
|
name = max(names_,
|
||||||
|
key=lambda n: tuple(
|
||||||
|
tuple(
|
||||||
|
# make sure to use the rebuilt table
|
||||||
|
(getattr(table_[n], k),)
|
||||||
|
if getattr(table_.get(n), k, None) is not None
|
||||||
|
else ()
|
||||||
|
for k in ([k] if k else [
|
||||||
|
k for k in Result._sort if k in fields])
|
||||||
|
if k in fields)
|
||||||
|
for k, reverse in it.chain(
|
||||||
|
sort or [],
|
||||||
|
[(None, False)])))
|
||||||
|
|
||||||
|
r = table_[name]
|
||||||
|
is_last = not r.children
|
||||||
|
|
||||||
|
line = table_entry(name, r)
|
||||||
|
line = [x if isinstance(x, tuple) else (x, [])
|
||||||
|
for x in line]
|
||||||
|
print('%s%-*s %s' % (
|
||||||
|
prefixes[0+is_last],
|
||||||
|
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
||||||
|
' '.join('%*s%-*s' % (
|
||||||
|
widths[i], x[0],
|
||||||
|
notes[i],
|
||||||
|
' (%s)' % ', '.join(it.chain(
|
||||||
|
x[1], ['cycle detected']))
|
||||||
|
if i == len(widths)-1 and name in seen
|
||||||
|
else ' (%s)' % ', '.join(x[1]) if x[1]
|
||||||
|
else '')
|
||||||
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
# found a cycle?
|
||||||
|
if name in seen:
|
||||||
|
return
|
||||||
|
|
||||||
|
# recurse?
|
||||||
|
if depth_ > 1:
|
||||||
|
recurse(
|
||||||
|
r.children,
|
||||||
|
depth_-1,
|
||||||
|
seen | {name},
|
||||||
|
prefixes)
|
||||||
|
|
||||||
|
else:
|
||||||
|
def recurse(results_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
# rebuild our tables at each layer
|
# rebuild our tables at each layer
|
||||||
table_ = {
|
table_ = {
|
||||||
','.join(str(getattr(r, k) or '') for k in by): r
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
@@ -890,20 +952,31 @@ def table(Result, results, diff_results=None, *,
|
|||||||
is_last = (i == len(names_)-1)
|
is_last = (i == len(names_)-1)
|
||||||
|
|
||||||
line = table_entry(name, r)
|
line = table_entry(name, r)
|
||||||
line = [x if isinstance(x, tuple) else (x, []) for x in line]
|
line = [x if isinstance(x, tuple) else (x, [])
|
||||||
|
for x in line]
|
||||||
print('%s%-*s %s' % (
|
print('%s%-*s %s' % (
|
||||||
prefixes[0+is_last],
|
prefixes[0+is_last],
|
||||||
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
||||||
' '.join('%*s%-*s' % (
|
' '.join('%*s%-*s' % (
|
||||||
widths[i], x[0],
|
widths[i], x[0],
|
||||||
notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
|
notes[i],
|
||||||
|
' (%s)' % ', '.join(it.chain(
|
||||||
|
x[1], ['cycle detected']))
|
||||||
|
if i == len(widths)-1 and name in seen
|
||||||
|
else ' (%s)' % ', '.join(x[1]) if x[1]
|
||||||
|
else '')
|
||||||
for i, x in enumerate(line[1:], 1))))
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
# found a cycle?
|
||||||
|
if name in seen:
|
||||||
|
continue
|
||||||
|
|
||||||
# recurse?
|
# recurse?
|
||||||
if depth_ > 1:
|
if depth_ > 1:
|
||||||
recurse(
|
recurse(
|
||||||
r.children,
|
r.children,
|
||||||
depth_-1,
|
depth_-1,
|
||||||
|
seen | {name},
|
||||||
(prefixes[2+is_last] + "|-> ",
|
(prefixes[2+is_last] + "|-> ",
|
||||||
prefixes[2+is_last] + "'-> ",
|
prefixes[2+is_last] + "'-> ",
|
||||||
prefixes[2+is_last] + "| ",
|
prefixes[2+is_last] + "| ",
|
||||||
@@ -923,6 +996,7 @@ def table(Result, results, diff_results=None, *,
|
|||||||
recurse(
|
recurse(
|
||||||
table[name].children,
|
table[name].children,
|
||||||
depth-1,
|
depth-1,
|
||||||
|
{name},
|
||||||
("|-> ",
|
("|-> ",
|
||||||
"'-> ",
|
"'-> ",
|
||||||
"| ",
|
"| ",
|
||||||
@@ -1049,8 +1123,10 @@ def report(perf_paths, *,
|
|||||||
else:
|
else:
|
||||||
args['color'] = False
|
args['color'] = False
|
||||||
|
|
||||||
# depth of 0 == m.inf
|
# figure out depth
|
||||||
if args.get('depth') == 0:
|
if args.get('depth') is None:
|
||||||
|
args['depth'] = m.inf if args.get('hot') else 1
|
||||||
|
elif args.get('depth') == 0:
|
||||||
args['depth'] = m.inf
|
args['depth'] = m.inf
|
||||||
|
|
||||||
# find sizes
|
# find sizes
|
||||||
@@ -1278,6 +1354,10 @@ if __name__ == "__main__":
|
|||||||
const=0,
|
const=0,
|
||||||
help="Depth of function calls to show. 0 shows all calls but may not "
|
help="Depth of function calls to show. 0 shows all calls but may not "
|
||||||
"terminate!")
|
"terminate!")
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--hot',
|
||||||
|
action='store_true',
|
||||||
|
help="Show only the hot path for each function call.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-A', '--annotate',
|
'-A', '--annotate',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
+95
-15
@@ -639,7 +639,8 @@ def table(Result, results, diff_results=None, *,
|
|||||||
summary=False,
|
summary=False,
|
||||||
all=False,
|
all=False,
|
||||||
percent=False,
|
percent=False,
|
||||||
depth=1,
|
depth=None,
|
||||||
|
hot=False,
|
||||||
**_):
|
**_):
|
||||||
all_, all = all, __builtins__.all
|
all_, all = all, __builtins__.all
|
||||||
|
|
||||||
@@ -794,24 +795,25 @@ def table(Result, results, diff_results=None, *,
|
|||||||
|
|
||||||
if not summary:
|
if not summary:
|
||||||
# find the actual depth
|
# find the actual depth
|
||||||
#
|
|
||||||
# note unlike stack.py we can't end up with cycles here
|
|
||||||
depth_ = depth
|
depth_ = depth
|
||||||
if m.isinf(depth_):
|
if hot:
|
||||||
def rec_depth(results_):
|
depth_ = 2
|
||||||
|
elif m.isinf(depth_):
|
||||||
|
def rec_depth(results_, seen=set()):
|
||||||
# rebuild our tables at each layer
|
# rebuild our tables at each layer
|
||||||
table_ = {
|
table_ = {
|
||||||
','.join(str(getattr(r, k) or '') for k in by): r
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
for r in results_}
|
for r in results_}
|
||||||
names_ = list(table_.keys())
|
names_ = list(table_.keys())
|
||||||
|
|
||||||
return max((
|
return max(
|
||||||
rec_depth(table_[name].children)
|
(rec_depth(table_[name].children, seen | {name})
|
||||||
for name in names_),
|
for name in names_
|
||||||
|
if name not in seen),
|
||||||
default=-1) + 1
|
default=-1) + 1
|
||||||
|
|
||||||
depth_ = max((
|
depth_ = max(
|
||||||
rec_depth(table[name].children)
|
(rec_depth(table[name].children, {name})
|
||||||
for name in names
|
for name in names
|
||||||
if name in table),
|
if name in table),
|
||||||
default=-1) + 1
|
default=-1) + 1
|
||||||
@@ -828,7 +830,67 @@ def table(Result, results, diff_results=None, *,
|
|||||||
for i, x in enumerate(lines[0][1:], 1))))
|
for i, x in enumerate(lines[0][1:], 1))))
|
||||||
|
|
||||||
if not summary:
|
if not summary:
|
||||||
def recurse(results_, depth_, prefixes=('', '', '', '')):
|
if hot:
|
||||||
|
def recurse(results_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
|
# rebuild our tables at each layer
|
||||||
|
table_ = {
|
||||||
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
|
for r in results_}
|
||||||
|
names_ = list(table_.keys())
|
||||||
|
if not names_:
|
||||||
|
return
|
||||||
|
|
||||||
|
# find the "hottest" path at each step, we use
|
||||||
|
# the sort field if requested, but ignore reversedness
|
||||||
|
name = max(names_,
|
||||||
|
key=lambda n: tuple(
|
||||||
|
tuple(
|
||||||
|
# make sure to use the rebuilt table
|
||||||
|
(getattr(table_[n], k),)
|
||||||
|
if getattr(table_.get(n), k, None) is not None
|
||||||
|
else ()
|
||||||
|
for k in ([k] if k else [
|
||||||
|
k for k in Result._sort if k in fields])
|
||||||
|
if k in fields)
|
||||||
|
for k, reverse in it.chain(
|
||||||
|
sort or [],
|
||||||
|
[(None, False)])))
|
||||||
|
|
||||||
|
r = table_[name]
|
||||||
|
is_last = not r.children
|
||||||
|
|
||||||
|
line = table_entry(name, r)
|
||||||
|
line = [x if isinstance(x, tuple) else (x, [])
|
||||||
|
for x in line]
|
||||||
|
print('%s%-*s %s' % (
|
||||||
|
prefixes[0+is_last],
|
||||||
|
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
||||||
|
' '.join('%*s%-*s' % (
|
||||||
|
widths[i], x[0],
|
||||||
|
notes[i],
|
||||||
|
' (%s)' % ', '.join(it.chain(
|
||||||
|
x[1], ['cycle detected']))
|
||||||
|
if i == len(widths)-1 and name in seen
|
||||||
|
else ' (%s)' % ', '.join(x[1]) if x[1]
|
||||||
|
else '')
|
||||||
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
# found a cycle?
|
||||||
|
if name in seen:
|
||||||
|
return
|
||||||
|
|
||||||
|
# recurse?
|
||||||
|
if depth_ > 1:
|
||||||
|
recurse(
|
||||||
|
r.children,
|
||||||
|
depth_-1,
|
||||||
|
seen | {name},
|
||||||
|
prefixes)
|
||||||
|
|
||||||
|
else:
|
||||||
|
def recurse(results_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
# rebuild our tables at each layer
|
# rebuild our tables at each layer
|
||||||
table_ = {
|
table_ = {
|
||||||
','.join(str(getattr(r, k) or '') for k in by): r
|
','.join(str(getattr(r, k) or '') for k in by): r
|
||||||
@@ -854,20 +916,31 @@ def table(Result, results, diff_results=None, *,
|
|||||||
is_last = (i == len(names_)-1)
|
is_last = (i == len(names_)-1)
|
||||||
|
|
||||||
line = table_entry(name, r)
|
line = table_entry(name, r)
|
||||||
line = [x if isinstance(x, tuple) else (x, []) for x in line]
|
line = [x if isinstance(x, tuple) else (x, [])
|
||||||
|
for x in line]
|
||||||
print('%s%-*s %s' % (
|
print('%s%-*s %s' % (
|
||||||
prefixes[0+is_last],
|
prefixes[0+is_last],
|
||||||
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
||||||
' '.join('%*s%-*s' % (
|
' '.join('%*s%-*s' % (
|
||||||
widths[i], x[0],
|
widths[i], x[0],
|
||||||
notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
|
notes[i],
|
||||||
|
' (%s)' % ', '.join(it.chain(
|
||||||
|
x[1], ['cycle detected']))
|
||||||
|
if i == len(widths)-1 and name in seen
|
||||||
|
else ' (%s)' % ', '.join(x[1]) if x[1]
|
||||||
|
else '')
|
||||||
for i, x in enumerate(line[1:], 1))))
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
# found a cycle?
|
||||||
|
if name in seen:
|
||||||
|
continue
|
||||||
|
|
||||||
# recurse?
|
# recurse?
|
||||||
if depth_ > 1:
|
if depth_ > 1:
|
||||||
recurse(
|
recurse(
|
||||||
r.children,
|
r.children,
|
||||||
depth_-1,
|
depth_-1,
|
||||||
|
seen | {name},
|
||||||
(prefixes[2+is_last] + "|-> ",
|
(prefixes[2+is_last] + "|-> ",
|
||||||
prefixes[2+is_last] + "'-> ",
|
prefixes[2+is_last] + "'-> ",
|
||||||
prefixes[2+is_last] + "| ",
|
prefixes[2+is_last] + "| ",
|
||||||
@@ -887,6 +960,7 @@ def table(Result, results, diff_results=None, *,
|
|||||||
recurse(
|
recurse(
|
||||||
table[name].children,
|
table[name].children,
|
||||||
depth-1,
|
depth-1,
|
||||||
|
{name},
|
||||||
("|-> ",
|
("|-> ",
|
||||||
"'-> ",
|
"'-> ",
|
||||||
"| ",
|
"| ",
|
||||||
@@ -1027,8 +1101,10 @@ def report(obj_path='', trace_paths=[], *,
|
|||||||
else:
|
else:
|
||||||
args['color'] = False
|
args['color'] = False
|
||||||
|
|
||||||
# depth of 0 == m.inf
|
# figure out depth
|
||||||
if args.get('depth') == 0:
|
if args.get('depth') is None:
|
||||||
|
args['depth'] = m.inf if args.get('hot') else 1
|
||||||
|
elif args.get('depth') == 0:
|
||||||
args['depth'] = m.inf
|
args['depth'] = m.inf
|
||||||
|
|
||||||
# find sizes
|
# find sizes
|
||||||
@@ -1239,6 +1315,10 @@ if __name__ == "__main__":
|
|||||||
const=0,
|
const=0,
|
||||||
help="Depth of function calls to show. 0 shows all calls but may not "
|
help="Depth of function calls to show. 0 shows all calls but may not "
|
||||||
"terminate!")
|
"terminate!")
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--hot',
|
||||||
|
action='store_true',
|
||||||
|
help="Show only the hot path for each function call.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-A', '--annotate',
|
'-A', '--annotate',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
+107
-28
@@ -321,7 +321,8 @@ def table(Result, results, diff_results=None, *,
|
|||||||
summary=False,
|
summary=False,
|
||||||
all=False,
|
all=False,
|
||||||
percent=False,
|
percent=False,
|
||||||
depth=1,
|
depth=None,
|
||||||
|
hot=False,
|
||||||
**_):
|
**_):
|
||||||
all_, all = all, __builtins__.all
|
all_, all = all, __builtins__.all
|
||||||
|
|
||||||
@@ -477,27 +478,26 @@ def table(Result, results, diff_results=None, *,
|
|||||||
if not summary:
|
if not summary:
|
||||||
# find the actual depth
|
# find the actual depth
|
||||||
depth_ = depth
|
depth_ = depth
|
||||||
if m.isinf(depth_):
|
if hot:
|
||||||
def rec_depth(names_, seen=set()):
|
depth_ = 2
|
||||||
depth_ = -1
|
elif m.isinf(depth_):
|
||||||
for name in names_:
|
def rec_depth(children_, seen=set()):
|
||||||
# found a cycle?
|
names_ = {
|
||||||
if name in seen:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# recurse?
|
|
||||||
if name in table:
|
|
||||||
children = {
|
|
||||||
','.join(str(getattr(Result(*c), k) or '')
|
','.join(str(getattr(Result(*c), k) or '')
|
||||||
for k in by)
|
for k in by)
|
||||||
for c in table[name].children}
|
for c in children_}
|
||||||
depth_ = max(depth_,
|
|
||||||
rec_depth(
|
|
||||||
[n for n in names if n in children],
|
|
||||||
seen | {name}))
|
|
||||||
return depth_ + 1
|
|
||||||
|
|
||||||
depth_ = rec_depth(names)
|
return max(
|
||||||
|
(rec_depth(table[name].children, seen | {name})
|
||||||
|
for name in names_
|
||||||
|
if name not in seen),
|
||||||
|
default=-1) + 1
|
||||||
|
|
||||||
|
depth_ = max(
|
||||||
|
(rec_depth(table[name].children, {name})
|
||||||
|
for name in names
|
||||||
|
if name in table),
|
||||||
|
default=-1) + 1
|
||||||
|
|
||||||
# adjust the name width based on the call depth
|
# adjust the name width based on the call depth
|
||||||
widths[0] += 4*max(depth_-1, 0)
|
widths[0] += 4*max(depth_-1, 0)
|
||||||
@@ -513,7 +513,68 @@ def table(Result, results, diff_results=None, *,
|
|||||||
if not summary:
|
if not summary:
|
||||||
line_table = {n: l for n, l in zip(names, lines[1:-1])}
|
line_table = {n: l for n, l in zip(names, lines[1:-1])}
|
||||||
|
|
||||||
def recurse(names_, depth_, seen=set(), prefixes=('', '', '', '')):
|
if hot:
|
||||||
|
def recurse(children_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
|
names_ = {','.join(str(getattr(Result(*c), k) or '')
|
||||||
|
for k in by)
|
||||||
|
for c in children_}
|
||||||
|
if not names_:
|
||||||
|
return
|
||||||
|
|
||||||
|
# find the "hottest" path at each step, we use
|
||||||
|
# the sort field if requested, but ignore reversedness
|
||||||
|
name = max(names_,
|
||||||
|
key=lambda n: tuple(
|
||||||
|
tuple(
|
||||||
|
(getattr(table[n], k),)
|
||||||
|
if getattr(table.get(n), k, None) is not None
|
||||||
|
else ()
|
||||||
|
for k in ([k] if k else [
|
||||||
|
k for k in Result._sort if k in fields])
|
||||||
|
if k in fields)
|
||||||
|
for k, reverse in it.chain(
|
||||||
|
sort or [],
|
||||||
|
[(None, False)])))
|
||||||
|
|
||||||
|
if name in line_table:
|
||||||
|
line = line_table[name]
|
||||||
|
is_last = not table[name].children
|
||||||
|
|
||||||
|
print('%s%-*s %s' % (
|
||||||
|
prefixes[0+is_last],
|
||||||
|
widths[0] - len(prefixes[0+is_last]), line[0][0],
|
||||||
|
' '.join('%*s%-*s' % (
|
||||||
|
widths[i], x[0],
|
||||||
|
notes[i],
|
||||||
|
' (%s)' % ', '.join(it.chain(
|
||||||
|
x[1], ['cycle detected']))
|
||||||
|
if i == len(widths)-1 and name in seen
|
||||||
|
else ' (%s)' % ', '.join(x[1]) if x[1]
|
||||||
|
else '')
|
||||||
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
# found a cycle?
|
||||||
|
if name in seen:
|
||||||
|
return
|
||||||
|
|
||||||
|
# recurse?
|
||||||
|
if depth_ > 1:
|
||||||
|
recurse(
|
||||||
|
table[name].children,
|
||||||
|
depth_-1,
|
||||||
|
seen | {name},
|
||||||
|
prefixes)
|
||||||
|
|
||||||
|
else:
|
||||||
|
def recurse(children_, depth_, seen=set(),
|
||||||
|
prefixes=('', '', '', '')):
|
||||||
|
# note we're maintaining sort order
|
||||||
|
names_ = {','.join(str(getattr(Result(*c), k) or '')
|
||||||
|
for k in by)
|
||||||
|
for c in children_}
|
||||||
|
names_ = [n for n in names if n in names_]
|
||||||
|
|
||||||
for i, name in enumerate(names_):
|
for i, name in enumerate(names_):
|
||||||
if name not in line_table:
|
if name not in line_table:
|
||||||
continue
|
continue
|
||||||
@@ -538,13 +599,9 @@ def table(Result, results, diff_results=None, *,
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# recurse?
|
# recurse?
|
||||||
if name in table and depth_ > 1:
|
if depth_ > 1:
|
||||||
children = {
|
|
||||||
','.join(str(getattr(Result(*c), k) or '') for k in by)
|
|
||||||
for c in table[name].children}
|
|
||||||
recurse(
|
recurse(
|
||||||
# note we're maintaining sort order
|
table[name].children,
|
||||||
[n for n in names if n in children],
|
|
||||||
depth_-1,
|
depth_-1,
|
||||||
seen | {name},
|
seen | {name},
|
||||||
(prefixes[2+is_last] + "|-> ",
|
(prefixes[2+is_last] + "|-> ",
|
||||||
@@ -552,7 +609,24 @@ def table(Result, results, diff_results=None, *,
|
|||||||
prefixes[2+is_last] + "| ",
|
prefixes[2+is_last] + "| ",
|
||||||
prefixes[2+is_last] + " "))
|
prefixes[2+is_last] + " "))
|
||||||
|
|
||||||
recurse(names, depth)
|
# make the top layer a special case
|
||||||
|
for name, line in zip(names, lines[1:-1]):
|
||||||
|
print('%-*s %s' % (
|
||||||
|
widths[0], line[0][0],
|
||||||
|
' '.join('%*s%-*s' % (
|
||||||
|
widths[i], x[0],
|
||||||
|
notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
|
||||||
|
for i, x in enumerate(line[1:], 1))))
|
||||||
|
|
||||||
|
if name in table and depth > 1:
|
||||||
|
recurse(
|
||||||
|
table[name].children,
|
||||||
|
depth-1,
|
||||||
|
{name},
|
||||||
|
("|-> ",
|
||||||
|
"'-> ",
|
||||||
|
"| ",
|
||||||
|
" "))
|
||||||
|
|
||||||
print('%-*s %s' % (
|
print('%-*s %s' % (
|
||||||
widths[0], lines[-1][0][0],
|
widths[0], lines[-1][0][0],
|
||||||
@@ -568,8 +642,9 @@ def main(ci_paths,
|
|||||||
defines=[],
|
defines=[],
|
||||||
sort=None,
|
sort=None,
|
||||||
**args):
|
**args):
|
||||||
|
# figure out depth
|
||||||
if args.get('depth') is None:
|
if args.get('depth') is None:
|
||||||
args['depth'] = 1
|
args['depth'] = m.inf if args.get('hot') else 1
|
||||||
elif args.get('depth') == 0:
|
elif args.get('depth') == 0:
|
||||||
args['depth'] = m.inf
|
args['depth'] = m.inf
|
||||||
|
|
||||||
@@ -760,6 +835,10 @@ if __name__ == "__main__":
|
|||||||
const=0,
|
const=0,
|
||||||
help="Depth of function calls to show. 0 shows all calls but may not "
|
help="Depth of function calls to show. 0 shows all calls but may not "
|
||||||
"terminate!")
|
"terminate!")
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--hot',
|
||||||
|
action='store_true',
|
||||||
|
help="Show only the hot path for each function call.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-e', '--error-on-recursion',
|
'-e', '--error-on-recursion',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
Reference in New Issue
Block a user