From b2768becaa1f837ba40b71a6748e93fc59766b5c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 28 Feb 2025 02:07:20 -0600 Subject: [PATCH] scripts: Added -l/--labels to csv.py This gives csv.py access to a hidden feature in our table renderer used by some of the other scripts: fields that affect by-field grouping, but aren't actually printed. For example, this prevents summing same named functions in different files, but only shows the function name in the table render: $ ./scripts/csv.py lfs.code.csv -bfile -bfunction -lfunction function size lfs_alloc 398 lfs_alloc_discard 31 lfs_alloc_findfree 77 ... This is especially useful when enumerating results. For example, this prevents any summing without extra table noise: $ ./scripts/csv.py lfs.code.csv -i -bfunction -fsize -lfunction function size lfs_alloc 398 lfs_alloc_discard 31 lfs_alloc_findfree 77 ... I also tweaked -b/--by field defaults a bit to account to enumerate/label fields a bit better. --- scripts/code.py | 32 +++++++++---- scripts/cov.py | 32 +++++++++---- scripts/csv.py | 114 +++++++++++++++++++++++++++++++++------------ scripts/ctx.py | 35 +++++++++----- scripts/data.py | 32 +++++++++---- scripts/perf.py | 35 +++++++++----- scripts/perfbd.py | 35 +++++++++----- scripts/stack.py | 35 +++++++++----- scripts/structs.py | 35 +++++++++----- 9 files changed, 270 insertions(+), 115 deletions(-) diff --git a/scripts/code.py b/scripts/code.py index 3398c274..d668f0cc 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -583,6 +583,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -592,8 +595,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -637,7 +638,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -663,7 +664,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -722,6 +725,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -793,13 +797,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -807,7 +820,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1014,8 +1027,7 @@ def main(obj_paths, *, fields=fields, **args) if args.get('output_json'): - write_csv(args['output_json'], CodeResult, results, - json=True, + write_csv(args['output_json'], CodeResult, results, json=True, by=by, fields=fields, **args) diff --git a/scripts/cov.py b/scripts/cov.py index b9b4b948..e35a11e4 100755 --- a/scripts/cov.py +++ b/scripts/cov.py @@ -444,6 +444,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -453,8 +456,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -498,7 +499,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -524,7 +525,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -583,6 +586,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -654,13 +658,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -668,7 +681,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -959,8 +972,7 @@ def main(gcda_paths, *, fields=fields, **args) if args.get('output_json'): - write_csv(args['output_json'], CovResult, results, - json=True, + write_csv(args['output_json'], CovResult, results, json=True, by=by, fields=fields, **args) diff --git a/scripts/csv.py b/scripts/csv.py index 78b71ab7..a0d92e32 100755 --- a/scripts/csv.py +++ b/scripts/csv.py @@ -1397,20 +1397,12 @@ def compile(fields_, results, exprs=[], defines=[], sort=None, - enumerate=None, children=None, hot=None, notes=None): - import builtins - enumerate_, enumerate = enumerate, builtins.enumerate - by = by.copy() fields = fields.copy() - # make sure enumerate fields are included - if enumerate_ is not None: - if enumerate_ not in by: - by.insert(0, enumerate_) # make sure define fields are included for k, _ in defines: if k not in by and k not in fields: @@ -1430,6 +1422,10 @@ def compile(fields_, results, for k in fields)) types = {} for k in fields__: + # check if dependency is in original fields + # + # it's tempting to also allow enumerate fields here, but this + # currently doesn't work when hotifying if k not in fields_: print("error: no field %r?" % k, file=sys.stderr) @@ -1472,17 +1468,14 @@ def compile(fields_, results, r__ = r_.copy() for k, expr in exprs.items(): r__[k] = expr.eval(r_) - r_ = r__ # evaluate mods - r__ = r_.copy() for k, m in mods.items(): - r__[k] = punescape(m, r_) - r_ = r__ + r__[k] = punescape(m, r) # return result return cls.__mro__[1].__new__(cls, **( - {k: r_.get(k, '') for k in by} - | {k: ([r_[k]], 1) if k in r_ else ([], 0) + {k: r__.get(k, '') for k in by} + | {k: ([r__[k]], 1) if k in r__ else ([], 0) for k in fields} | ({children: r[children] if children in r else []} if children is not None else {}) @@ -1555,7 +1548,7 @@ def homogenize(Result, results, *, results_.append(Result(**( r # enumerate? - | ({enumerate_: RInt(i)} + | ({enumerate_: i} if enumerate_ is not None else {}) # recurse? @@ -1704,6 +1697,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -1713,8 +1709,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -1758,7 +1752,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -1784,7 +1778,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -1843,6 +1839,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -1914,13 +1911,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -1928,7 +1934,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -2107,6 +2113,7 @@ def main(csv_paths, *, defines=[], sort=None, enumerate=None, + labels=None, depth=None, children=None, hot=None, @@ -2119,11 +2126,32 @@ def main(csv_paths, *, if args.get('help_exprs'): return RExpr.help() - if by is None and fields is None: + if by is None and enumerate_ is None and labels is None and fields is None: print("error: needs --by or --fields to figure out fields", file=sys.stderr) sys.exit(-1) + if enumerate_ is not None: + if len(enumerate_) > 1: + print("error: multiple --enumerate fields currently not supported", + file=sys.stderr) + sys.exit(-1) + enumerate_ = enumerate_[0] + + if children is not None: + if len(children) > 1: + print("error: multiple --children fields currently not supported", + file=sys.stderr) + sys.exit(-1) + children = children[0] + + if notes is not None: + if len(notes) > 1: + print("error: multiple --notes fields currently not supported", + file=sys.stderr) + sys.exit(-1) + notes = notes[0] + # recursive results imply --children if (depth is not None or hot is not None) and children is None: children = 'children' @@ -2139,7 +2167,9 @@ def main(csv_paths, *, # by supports mods => -ba=%(b)s # fields/sort/hot support exprs => -fa=b+c mods = [(k, v) - for k, v in (by or []) + for k, v in it.chain( + by or [], + labels or []) if v is not None] exprs = [(k, v) for k, v in it.chain( @@ -2153,9 +2183,22 @@ def main(csv_paths, *, fields = [k for k, _ in fields] if sort is not None: sort = [(k, reverse) for (k, v), reverse in sort] + if labels is not None: + labels = [k for k, _ in labels] if hot is not None: hot = [(k, reverse) for (k, v), reverse in hot] + # include enumerate and label fields in by + if enumerate_ is not None: + by = by or [] + if enumerate_ not in by: + by.insert(0, enumerate_) + if labels is not None: + by = by or [] + for k in labels: + if k not in by: + by.append(k) + # find results if not args.get('use', None): # not enough info? @@ -2185,7 +2228,6 @@ def main(csv_paths, *, if k not in (fields or []) and not any(k == k_ for k_, _ in defines) and not any(k == k_ for k_, _ in (sort or [])) - and k != enumerate_ and k != children and not any(k == k_ for k_, _ in (hot or [])) and k != notes @@ -2199,7 +2241,6 @@ def main(csv_paths, *, if k not in (by or []) and not any(k == k_ for k_, _ in defines) and not any(k == k_ for k_, _ in (sort or [])) - and k != enumerate_ and k != children and not any(k == k_ for k_, _ in (hot or [])) and k != notes @@ -2215,7 +2256,6 @@ def main(csv_paths, *, exprs=exprs, defines=defines, sort=sort, - enumerate=enumerate_, children=children, hot=hot, notes=notes) @@ -2246,8 +2286,7 @@ def main(csv_paths, *, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], Result, results, - json=True, + write_csv(args['output_json'], Result, results, json=True, by=by, fields=fields, depth=depth, @@ -2277,6 +2316,7 @@ def main(csv_paths, *, by=by, fields=fields, sort=sort, + labels=labels, depth=depth, **args) @@ -2389,8 +2429,20 @@ if __name__ == "__main__": '-i', '--enumerate', nargs='?', const='i', + action='append', help="Field to use for enumerating results. This will prevent " "result folding.") + parser.add_argument( + '-l', '--label', + dest='labels', + action='append', + type=lambda x: ( + lambda k, v=None: ( + k.strip(), + v.strip() if v is not None else None) + )(*x.split('=', 1)), + help="Field to use for labeling results. This defaults to all " + "-b/--by fields. Can be assigned a string with %% modifiers.") parser.add_argument( '-z', '--depth', nargs='?', @@ -2402,6 +2454,7 @@ if __name__ == "__main__": '-Z', '--children', nargs='?', const='children', + action='append', help="Field to use for recursive results. This expects a list " "and really only works with JSON input.") class AppendHot(argparse.Action): @@ -2437,6 +2490,7 @@ if __name__ == "__main__": '-N', '--notes', nargs='?', const='notes', + action='append', help="Field to use for notes.") parser.add_argument( '--no-header', diff --git a/scripts/ctx.py b/scripts/ctx.py index b1cf4054..76e275b5 100755 --- a/scripts/ctx.py +++ b/scripts/ctx.py @@ -841,6 +841,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -850,8 +853,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -895,7 +896,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -921,7 +922,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -980,6 +983,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -1051,13 +1055,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -1065,7 +1078,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1290,8 +1303,7 @@ def main(obj_paths, *, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], CtxResult, results, - json=True, + write_csv(args['output_json'], CtxResult, results, json=True, by=by, fields=fields, depth=depth, @@ -1318,9 +1330,10 @@ def main(obj_paths, *, # print table if not args.get('quiet'): table(CtxResult, results, diff_results, - by=by if by is not None else ['function'], + by=by if by is not None else ['z', 'i', 'function'], fields=fields if fields is not None else ['size'], sort=sort, + labels=by if by is not None else ['function'], depth=depth, **args) diff --git a/scripts/data.py b/scripts/data.py index e8959c4e..f77301f7 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -583,6 +583,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -592,8 +595,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -637,7 +638,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -663,7 +664,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -722,6 +725,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -793,13 +797,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -807,7 +820,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1014,8 +1027,7 @@ def main(obj_paths, *, fields=fields, **args) if args.get('output_json'): - write_csv(args['output_json'], DataResult, results, - json=True, + write_csv(args['output_json'], DataResult, results, json=True, by=by, fields=fields, **args) diff --git a/scripts/perf.py b/scripts/perf.py index 0d46303f..7fc27312 100755 --- a/scripts/perf.py +++ b/scripts/perf.py @@ -945,6 +945,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -954,8 +957,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -999,7 +1000,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -1025,7 +1026,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -1084,6 +1087,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -1155,13 +1159,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -1169,7 +1182,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1503,8 +1516,7 @@ def report(perf_paths, *, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], PerfResult, results, - json=True, + write_csv(args['output_json'], PerfResult, results, json=True, by=by, fields=fields, depth=depth, @@ -1539,12 +1551,13 @@ def report(perf_paths, *, else: # print table table(PerfResult, results, diff_results, - by=by if by is not None else ['function'], + by=by if by is not None else ['z', 'function'], fields=fields if fields is not None else ['cycles'] if not branches and not caches else ['bmisses', 'branches'] if branches else ['cmisses', 'caches'], sort=sort, + labels=by if by is not None else ['function'], depth=depth, **args) diff --git a/scripts/perfbd.py b/scripts/perfbd.py index e3f884e9..d095d3f0 100755 --- a/scripts/perfbd.py +++ b/scripts/perfbd.py @@ -915,6 +915,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -924,8 +927,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -969,7 +970,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -995,7 +996,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -1054,6 +1057,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -1125,13 +1129,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -1139,7 +1152,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1502,8 +1515,7 @@ def report(paths, *, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], PerfBdResult, results, - json=True, + write_csv(args['output_json'], PerfBdResult, results, json=True, by=by, fields=fields, depth=depth, @@ -1539,10 +1551,11 @@ def report(paths, *, else: # print table table(PerfBdResult, results, diff_results, - by=by if by is not None else ['function'], + by=by if by is not None else ['z', 'function'], fields=fields if fields is not None else ['readed', 'proged', 'erased'], sort=sort, + labels=by if by is not None else ['function'], depth=depth, **args) diff --git a/scripts/stack.py b/scripts/stack.py index 85561523..a9f66c9b 100755 --- a/scripts/stack.py +++ b/scripts/stack.py @@ -587,6 +587,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -596,8 +599,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -641,7 +642,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -667,7 +668,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -726,6 +729,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -797,13 +801,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -811,7 +824,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1036,8 +1049,7 @@ def main(ci_paths, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], StackResult, results, - json=True, + write_csv(args['output_json'], StackResult, results, json=True, by=by, fields=fields, depth=depth, @@ -1064,9 +1076,10 @@ def main(ci_paths, # print table if not args.get('quiet'): table(StackResult, results, diff_results, - by=by if by is not None else ['function'], + by=by if by is not None else ['z', 'function'], fields=fields if fields is not None else ['frame', 'limit'], sort=sort, + labels=by if by is not None else ['function'], depth=depth, **args) diff --git a/scripts/structs.py b/scripts/structs.py index a9623537..c8c71423 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -661,6 +661,9 @@ def table(Result, results, diff_results=None, *, by=None, fields=None, sort=None, + labels=None, + depth=1, + hot=None, diff=None, percent=None, all=False, @@ -670,8 +673,6 @@ def table(Result, results, diff_results=None, *, no_total=False, small_table=False, summary=False, - depth=1, - hot=None, **_): import builtins all_, all = all, builtins.all @@ -715,7 +716,7 @@ def table(Result, results, diff_results=None, *, # header if not no_header: header = ['%s%s' % ( - ','.join(by), + ','.join(labels if labels is not None else by), ' (%d added, %d removed)' % ( sum(1 for n in table if n not in diff_table), sum(1 for n in diff_table if n not in table)) @@ -741,7 +742,9 @@ def table(Result, results, diff_results=None, *, # entry helper def table_entry(name, r, diff_r=None): + # prepend name entry = [name] + # normal entry? if ((compare is None or r == compare_r) and not percent @@ -800,6 +803,7 @@ def table(Result, results, diff_results=None, *, types[k].ratio( getattr(r, k, None), getattr(diff_r, k, None))))) + # append any notes if hasattr(Result, '_notes') and r is not None: notes = sorted(getattr(r, Result._notes)) @@ -871,13 +875,22 @@ def table(Result, results, diff_results=None, *, # and finally by name (diffs may be missing results) n)) - for i, n in enumerate(names_): + for i, name in enumerate(names_): # find comparable results - r = table_.get(n) - diff_r = diff_table_.get(n) + r = table_.get(name) + diff_r = diff_table_.get(name) + + # figure out a good label + if labels is not None: + label = ','.join(str(getattr(r, k) + if getattr(r, k) is not None + else '') + for k in labels) + else: + label = name # build line - line = table_entry(n, r, diff_r) + line = table_entry(label, r, diff_r) # add prefixes line = [x if isinstance(x, tuple) else (x, []) for x in line] @@ -885,7 +898,7 @@ def table(Result, results, diff_results=None, *, lines.append(line) # recurse? - if n in table_ and depth_ > 1: + if name in table_ and depth_ > 1: table_recurse( getattr(r, Result._children), getattr(diff_r, Result._children, None) or [], @@ -1110,8 +1123,7 @@ def main(obj_paths, *, depth=depth, **args) if args.get('output_json'): - write_csv(args['output_json'], StructResult, results, - json=True, + write_csv(args['output_json'], StructResult, results, json=True, by=by, fields=fields, depth=depth, @@ -1138,9 +1150,10 @@ def main(obj_paths, *, # print table if not args.get('quiet'): table(StructResult, results, diff_results, - by=by if by is not None else ['struct'], + by=by if by is not None else ['z', 'i', 'struct'], fields=fields if fields is not None else ['size', 'align'], sort=sort, + labels=by if by is not None else ['struct'], depth=depth, **args)