diff --git a/scripts/code.py b/scripts/code.py index 81bfa2d5..121cd561 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -380,6 +380,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, + depth=1, + hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -394,6 +397,35 @@ def table(Result, results, diff_results=None, *, if diff_results is not None: diff_results = fold(Result, diff_results, by=by) + # reduce children to hot paths? + if hot: + def rec_hot(results_, seen=set()): + if not results_: + return [] + + r = max(results_, + key=lambda r: tuple( + tuple((getattr(r, k),) + if getattr(r, 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 in it.chain(hot, [None]))) + + # found a cycle? + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): + return [] + + return [r._replace(children=[])] + rec_hot( + r.children, + seen | {tuple(getattr(r, k) for k in Result._by)}) + + results = [r._replace(children=rec_hot(r.children)) for r in results] + # organize by name table = { ','.join(str(getattr(r, k) or '') for k in by): r @@ -535,6 +567,59 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry + # recursive entry helper, only used by some scripts + def recurse(results_, depth_, seen=set(), + prefixes=('', '', '', '')): + # build the children table at each layer + results_ = fold(Result, results_, by=by) + table_ = { + ','.join(str(getattr(r, k) or '') for k in by): r + for r in results_} + names_ = list(table_.keys()) + + # sort the children layer + names_.sort() + if sort: + for k, reverse in reversed(sort): + names_.sort( + key=lambda n: 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])), + reverse=reverse ^ (not k or k in Result._fields)) + + for i, name in enumerate(names_): + r = table_[name] + is_last = (i == len(names_)-1) + + line = table_entry(name, r) + line = [x if isinstance(x, tuple) else (x, []) for x in line] + # add prefixes + line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) + # add cycle detection + if detect_cycles and name in seen: + line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) + lines.append(line) + + # found a cycle? + if detect_cycles and name in seen: + continue + + # recurse? + if depth_ > 1: + recurse(r.children, + depth_-1, + seen | {name}, + (prefixes[2+is_last] + "|-> ", + prefixes[2+is_last] + "'-> ", + prefixes[2+is_last] + "| ", + prefixes[2+is_last] + " ")) + # entries if (not summary) or compare: for name in names: @@ -545,6 +630,16 @@ def table(Result, results, diff_results=None, *, diff_r = diff_table.get(name) lines.append(table_entry(name, r, diff_r)) + # recursive entries + if name in table and depth > 1: + recurse(table[name].children, + depth-1, + {name}, + ("|-> ", + "'-> ", + "| ", + " ")) + # total, unless we're comparing if not (compare and not percent and not diff): r = next(iter(fold(Result, results, by=[])), None) diff --git a/scripts/cov.py b/scripts/cov.py index e18b309d..6fbcabae 100755 --- a/scripts/cov.py +++ b/scripts/cov.py @@ -390,6 +390,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, + depth=1, + hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -404,6 +407,35 @@ def table(Result, results, diff_results=None, *, if diff_results is not None: diff_results = fold(Result, diff_results, by=by) + # reduce children to hot paths? + if hot: + def rec_hot(results_, seen=set()): + if not results_: + return [] + + r = max(results_, + key=lambda r: tuple( + tuple((getattr(r, k),) + if getattr(r, 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 in it.chain(hot, [None]))) + + # found a cycle? + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): + return [] + + return [r._replace(children=[])] + rec_hot( + r.children, + seen | {tuple(getattr(r, k) for k in Result._by)}) + + results = [r._replace(children=rec_hot(r.children)) for r in results] + # organize by name table = { ','.join(str(getattr(r, k) or '') for k in by): r @@ -545,6 +577,59 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry + # recursive entry helper, only used by some scripts + def recurse(results_, depth_, seen=set(), + prefixes=('', '', '', '')): + # build the children table at each layer + results_ = fold(Result, results_, by=by) + table_ = { + ','.join(str(getattr(r, k) or '') for k in by): r + for r in results_} + names_ = list(table_.keys()) + + # sort the children layer + names_.sort() + if sort: + for k, reverse in reversed(sort): + names_.sort( + key=lambda n: 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])), + reverse=reverse ^ (not k or k in Result._fields)) + + for i, name in enumerate(names_): + r = table_[name] + is_last = (i == len(names_)-1) + + line = table_entry(name, r) + line = [x if isinstance(x, tuple) else (x, []) for x in line] + # add prefixes + line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) + # add cycle detection + if detect_cycles and name in seen: + line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) + lines.append(line) + + # found a cycle? + if detect_cycles and name in seen: + continue + + # recurse? + if depth_ > 1: + recurse(r.children, + depth_-1, + seen | {name}, + (prefixes[2+is_last] + "|-> ", + prefixes[2+is_last] + "'-> ", + prefixes[2+is_last] + "| ", + prefixes[2+is_last] + " ")) + # entries if (not summary) or compare: for name in names: @@ -555,6 +640,16 @@ def table(Result, results, diff_results=None, *, diff_r = diff_table.get(name) lines.append(table_entry(name, r, diff_r)) + # recursive entries + if name in table and depth > 1: + recurse(table[name].children, + depth-1, + {name}, + ("|-> ", + "'-> ", + "| ", + " ")) + # total, unless we're comparing if not (compare and not percent and not diff): r = next(iter(fold(Result, results, by=[])), None) diff --git a/scripts/csv.py b/scripts/csv.py index 0746cdb5..b70a2f4b 100755 --- a/scripts/csv.py +++ b/scripts/csv.py @@ -1405,6 +1405,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, + depth=1, + hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -1419,6 +1422,35 @@ def table(Result, results, diff_results=None, *, if diff_results is not None: diff_results = fold(Result, diff_results, by=by) + # reduce children to hot paths? + if hot: + def rec_hot(results_, seen=set()): + if not results_: + return [] + + r = max(results_, + key=lambda r: tuple( + tuple((getattr(r, k),) + if getattr(r, 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 in it.chain(hot, [None]))) + + # found a cycle? + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): + return [] + + return [r._replace(children=[])] + rec_hot( + r.children, + seen | {tuple(getattr(r, k) for k in Result._by)}) + + results = [r._replace(children=rec_hot(r.children)) for r in results] + # organize by name table = { ','.join(str(getattr(r, k) or '') for k in by): r @@ -1442,16 +1474,6 @@ def table(Result, results, diff_results=None, *, # sort again, now with diff info, note that python's sort is stable names.sort() - if compare: - names.sort( - key=lambda n: ( - table.get(n) == compare_result, - tuple( - types[k].ratio( - getattr(table.get(n), k, None), - getattr(compare_result, k, None)) - for k in fields)), - reverse=True) if compare: names.sort( key=lambda n: ( @@ -1570,6 +1592,59 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry + # recursive entry helper, only used by some scripts + def recurse(results_, depth_, seen=set(), + prefixes=('', '', '', '')): + # build the children table at each layer + results_ = fold(Result, results_, by=by) + table_ = { + ','.join(str(getattr(r, k) or '') for k in by): r + for r in results_} + names_ = list(table_.keys()) + + # sort the children layer + names_.sort() + if sort: + for k, reverse in reversed(sort): + names_.sort( + key=lambda n: 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])), + reverse=reverse ^ (not k or k in Result._fields)) + + for i, name in enumerate(names_): + r = table_[name] + is_last = (i == len(names_)-1) + + line = table_entry(name, r) + line = [x if isinstance(x, tuple) else (x, []) for x in line] + # add prefixes + line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) + # add cycle detection + if detect_cycles and name in seen: + line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) + lines.append(line) + + # found a cycle? + if detect_cycles and name in seen: + continue + + # recurse? + if depth_ > 1: + recurse(r.children, + depth_-1, + seen | {name}, + (prefixes[2+is_last] + "|-> ", + prefixes[2+is_last] + "'-> ", + prefixes[2+is_last] + "| ", + prefixes[2+is_last] + " ")) + # entries if (not summary) or compare: for name in names: @@ -1580,6 +1655,16 @@ def table(Result, results, diff_results=None, *, diff_r = diff_table.get(name) lines.append(table_entry(name, r, diff_r)) + # recursive entries + if name in table and depth > 1: + recurse(table[name].children, + depth-1, + {name}, + ("|-> ", + "'-> ", + "| ", + " ")) + # total, unless we're comparing if not (compare and not percent and not diff): r = next(iter(fold(Result, results, by=[])), None) diff --git a/scripts/data.py b/scripts/data.py index 7fb432f9..54d891ca 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -380,6 +380,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, + depth=1, + hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -394,6 +397,35 @@ def table(Result, results, diff_results=None, *, if diff_results is not None: diff_results = fold(Result, diff_results, by=by) + # reduce children to hot paths? + if hot: + def rec_hot(results_, seen=set()): + if not results_: + return [] + + r = max(results_, + key=lambda r: tuple( + tuple((getattr(r, k),) + if getattr(r, 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 in it.chain(hot, [None]))) + + # found a cycle? + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): + return [] + + return [r._replace(children=[])] + rec_hot( + r.children, + seen | {tuple(getattr(r, k) for k in Result._by)}) + + results = [r._replace(children=rec_hot(r.children)) for r in results] + # organize by name table = { ','.join(str(getattr(r, k) or '') for k in by): r @@ -535,6 +567,59 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry + # recursive entry helper, only used by some scripts + def recurse(results_, depth_, seen=set(), + prefixes=('', '', '', '')): + # build the children table at each layer + results_ = fold(Result, results_, by=by) + table_ = { + ','.join(str(getattr(r, k) or '') for k in by): r + for r in results_} + names_ = list(table_.keys()) + + # sort the children layer + names_.sort() + if sort: + for k, reverse in reversed(sort): + names_.sort( + key=lambda n: 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])), + reverse=reverse ^ (not k or k in Result._fields)) + + for i, name in enumerate(names_): + r = table_[name] + is_last = (i == len(names_)-1) + + line = table_entry(name, r) + line = [x if isinstance(x, tuple) else (x, []) for x in line] + # add prefixes + line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) + # add cycle detection + if detect_cycles and name in seen: + line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) + lines.append(line) + + # found a cycle? + if detect_cycles and name in seen: + continue + + # recurse? + if depth_ > 1: + recurse(r.children, + depth_-1, + seen | {name}, + (prefixes[2+is_last] + "|-> ", + prefixes[2+is_last] + "'-> ", + prefixes[2+is_last] + "| ", + prefixes[2+is_last] + " ")) + # entries if (not summary) or compare: for name in names: @@ -545,6 +630,16 @@ def table(Result, results, diff_results=None, *, diff_r = diff_table.get(name) lines.append(table_entry(name, r, diff_r)) + # recursive entries + if name in table and depth > 1: + recurse(table[name].children, + depth-1, + {name}, + ("|-> ", + "'-> ", + "| ", + " ")) + # total, unless we're comparing if not (compare and not percent and not diff): r = next(iter(fold(Result, results, by=[])), None) diff --git a/scripts/perf.py b/scripts/perf.py index 0fe37985..c1fd1029 100755 --- a/scripts/perf.py +++ b/scripts/perf.py @@ -696,8 +696,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, - depth=None, + depth=1, hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -731,7 +732,8 @@ def table(Result, results, diff_results=None, *, for k in it.chain(hot, [None]))) # found a cycle? - if tuple(getattr(r, k) for k in Result._by) in seen: + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): return [] return [r._replace(children=[])] + rec_hot( @@ -753,9 +755,9 @@ def table(Result, results, diff_results=None, *, or all_ or any( types[k].ratio( - getattr(table.get(name), k, None), - getattr(diff_table.get(name), k, None)) - for k in fields)] + getattr(table.get(name), k, None), + getattr(diff_table.get(name), k, None)) + for k in fields)] # find compare entry if there is one if compare: @@ -881,7 +883,7 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry - # recursive entry helper + # recursive entry helper, only used by some scripts def recurse(results_, depth_, seen=set(), prefixes=('', '', '', '')): # build the children table at each layer @@ -916,12 +918,12 @@ def table(Result, results, diff_results=None, *, # add prefixes line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) # add cycle detection - if name in seen: + if detect_cycles and name in seen: line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) lines.append(line) # found a cycle? - if name in seen: + if detect_cycles and name in seen: continue # recurse? diff --git a/scripts/perfbd.py b/scripts/perfbd.py index 130fdb0e..7f7f1025 100755 --- a/scripts/perfbd.py +++ b/scripts/perfbd.py @@ -660,8 +660,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, - depth=None, + depth=1, hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -695,7 +696,8 @@ def table(Result, results, diff_results=None, *, for k in it.chain(hot, [None]))) # found a cycle? - if tuple(getattr(r, k) for k in Result._by) in seen: + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): return [] return [r._replace(children=[])] + rec_hot( @@ -717,9 +719,9 @@ def table(Result, results, diff_results=None, *, or all_ or any( types[k].ratio( - getattr(table.get(name), k, None), - getattr(diff_table.get(name), k, None)) - for k in fields)] + getattr(table.get(name), k, None), + getattr(diff_table.get(name), k, None)) + for k in fields)] # find compare entry if there is one if compare: @@ -845,7 +847,7 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry - # recursive entry helper + # recursive entry helper, only used by some scripts def recurse(results_, depth_, seen=set(), prefixes=('', '', '', '')): # build the children table at each layer @@ -880,12 +882,12 @@ def table(Result, results, diff_results=None, *, # add prefixes line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) # add cycle detection - if name in seen: + if detect_cycles and name in seen: line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) lines.append(line) # found a cycle? - if name in seen: + if detect_cycles and name in seen: continue # recurse? diff --git a/scripts/stack.py b/scripts/stack.py index 4832d94f..fb4ef917 100755 --- a/scripts/stack.py +++ b/scripts/stack.py @@ -342,8 +342,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, - depth=None, + depth=1, hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -377,7 +378,8 @@ def table(Result, results, diff_results=None, *, for k in it.chain(hot, [None]))) # found a cycle? - if tuple(getattr(r, k) for k in Result._by) in seen: + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): return [] return [r._replace(children=[])] + rec_hot( @@ -399,9 +401,9 @@ def table(Result, results, diff_results=None, *, or all_ or any( types[k].ratio( - getattr(table.get(name), k, None), - getattr(diff_table.get(name), k, None)) - for k in fields)] + getattr(table.get(name), k, None), + getattr(diff_table.get(name), k, None)) + for k in fields)] # find compare entry if there is one if compare: @@ -527,7 +529,7 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry - # recursive entry helper + # recursive entry helper, only used by some scripts def recurse(results_, depth_, seen=set(), prefixes=('', '', '', '')): # build the children table at each layer @@ -562,12 +564,12 @@ def table(Result, results, diff_results=None, *, # add prefixes line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) # add cycle detection - if name in seen: + if detect_cycles and name in seen: line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) lines.append(line) # found a cycle? - if name in seen: + if detect_cycles and name in seen: continue # recurse? diff --git a/scripts/structs.py b/scripts/structs.py index ae423a1e..263f8f19 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -469,8 +469,9 @@ def table(Result, results, diff_results=None, *, all=False, compare=None, summary=False, - depth=None, + depth=1, hot=None, + detect_cycles=True, **_): all_, all = all, __builtins__.all @@ -504,12 +505,13 @@ def table(Result, results, diff_results=None, *, for k in it.chain(hot, [None]))) # found a cycle? - if id(r) in seen: + if (detect_cycles + and tuple(getattr(r, k) for k in Result._by) in seen): return [] return [r._replace(children=[])] + rec_hot( r.children, - seen | {id(r)}) + seen | {tuple(getattr(r, k) for k in Result._by)}) results = [r._replace(children=rec_hot(r.children)) for r in results] @@ -654,7 +656,7 @@ def table(Result, results, diff_results=None, *, getattr(diff_r, k, None))))) return entry - # recursive entry helper + # recursive entry helper, only used by some scripts def recurse(results_, depth_, seen=set(), prefixes=('', '', '', '')): # build the children table at each layer @@ -689,19 +691,19 @@ def table(Result, results, diff_results=None, *, # add prefixes line[0] = (prefixes[0+is_last] + line[0][0], line[0][1]) # add cycle detection - if id(r) in seen: + if detect_cycles and name in seen: line[-1] = (line[-1][0], line[-1][1] + ['cycle detected']) lines.append(line) # found a cycle? - if id(r) in seen: + if detect_cycles and name in seen: continue # recurse? if depth_ > 1: recurse(r.children, depth_-1, - seen | {id(r)}, + seen | {name}, (prefixes[2+is_last] + "|-> ", prefixes[2+is_last] + "'-> ", prefixes[2+is_last] + "| ", @@ -721,7 +723,7 @@ def table(Result, results, diff_results=None, *, if name in table and depth > 1: recurse(table[name].children, depth-1, - {id(r)}, + {name}, ("|-> ", "'-> ", "| ", @@ -863,6 +865,7 @@ def main(obj_paths, *, by=by if by is not None else ['struct'], fields=fields, sort=sort, + detect_cycles=False, **args)