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.
This commit is contained in:
Christopher Haster
2025-02-28 02:07:20 -06:00
parent 748815bb46
commit b2768becaa
9 changed files with 270 additions and 115 deletions

View File

@@ -583,6 +583,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -592,8 +595,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -637,7 +638,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -722,6 +725,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1014,8 +1027,7 @@ def main(obj_paths, *,
fields=fields, fields=fields,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], CodeResult, results, write_csv(args['output_json'], CodeResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
**args) **args)

View File

@@ -444,6 +444,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -453,8 +456,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -498,7 +499,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -583,6 +586,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -959,8 +972,7 @@ def main(gcda_paths, *,
fields=fields, fields=fields,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], CovResult, results, write_csv(args['output_json'], CovResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
**args) **args)

View File

@@ -1397,20 +1397,12 @@ def compile(fields_, results,
exprs=[], exprs=[],
defines=[], defines=[],
sort=None, sort=None,
enumerate=None,
children=None, children=None,
hot=None, hot=None,
notes=None): notes=None):
import builtins
enumerate_, enumerate = enumerate, builtins.enumerate
by = by.copy() by = by.copy()
fields = fields.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 # make sure define fields are included
for k, _ in defines: for k, _ in defines:
if k not in by and k not in fields: if k not in by and k not in fields:
@@ -1430,6 +1422,10 @@ def compile(fields_, results,
for k in fields)) for k in fields))
types = {} types = {}
for k in fields__: 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_: if k not in fields_:
print("error: no field %r?" % k, print("error: no field %r?" % k,
file=sys.stderr) file=sys.stderr)
@@ -1472,17 +1468,14 @@ def compile(fields_, results,
r__ = r_.copy() r__ = r_.copy()
for k, expr in exprs.items(): for k, expr in exprs.items():
r__[k] = expr.eval(r_) r__[k] = expr.eval(r_)
r_ = r__
# evaluate mods # evaluate mods
r__ = r_.copy()
for k, m in mods.items(): for k, m in mods.items():
r__[k] = punescape(m, r_) r__[k] = punescape(m, r)
r_ = r__
# return result # return result
return cls.__mro__[1].__new__(cls, **( return cls.__mro__[1].__new__(cls, **(
{k: r_.get(k, '') for k in by} {k: r__.get(k, '') for k in by}
| {k: ([r_[k]], 1) if k in r_ else ([], 0) | {k: ([r__[k]], 1) if k in r__ else ([], 0)
for k in fields} for k in fields}
| ({children: r[children] if children in r else []} | ({children: r[children] if children in r else []}
if children is not None else {}) if children is not None else {})
@@ -1555,7 +1548,7 @@ def homogenize(Result, results, *,
results_.append(Result(**( results_.append(Result(**(
r r
# enumerate? # enumerate?
| ({enumerate_: RInt(i)} | ({enumerate_: i}
if enumerate_ is not None if enumerate_ is not None
else {}) else {})
# recurse? # recurse?
@@ -1704,6 +1697,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -1713,8 +1709,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -1758,7 +1752,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -1843,6 +1839,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -2107,6 +2113,7 @@ def main(csv_paths, *,
defines=[], defines=[],
sort=None, sort=None,
enumerate=None, enumerate=None,
labels=None,
depth=None, depth=None,
children=None, children=None,
hot=None, hot=None,
@@ -2119,11 +2126,32 @@ def main(csv_paths, *,
if args.get('help_exprs'): if args.get('help_exprs'):
return RExpr.help() 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", print("error: needs --by or --fields to figure out fields",
file=sys.stderr) file=sys.stderr)
sys.exit(-1) 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 # recursive results imply --children
if (depth is not None or hot is not None) and children is None: if (depth is not None or hot is not None) and children is None:
children = 'children' children = 'children'
@@ -2139,7 +2167,9 @@ def main(csv_paths, *,
# by supports mods => -ba=%(b)s # by supports mods => -ba=%(b)s
# fields/sort/hot support exprs => -fa=b+c # fields/sort/hot support exprs => -fa=b+c
mods = [(k, v) mods = [(k, v)
for k, v in (by or []) for k, v in it.chain(
by or [],
labels or [])
if v is not None] if v is not None]
exprs = [(k, v) exprs = [(k, v)
for k, v in it.chain( for k, v in it.chain(
@@ -2153,9 +2183,22 @@ def main(csv_paths, *,
fields = [k for k, _ in fields] fields = [k for k, _ in fields]
if sort is not None: if sort is not None:
sort = [(k, reverse) for (k, v), reverse in sort] 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: if hot is not None:
hot = [(k, reverse) for (k, v), reverse in hot] 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 # find results
if not args.get('use', None): if not args.get('use', None):
# not enough info? # not enough info?
@@ -2185,7 +2228,6 @@ def main(csv_paths, *,
if k not in (fields or []) if k not in (fields or [])
and not any(k == k_ for k_, _ in defines) and not any(k == k_ for k_, _ in defines)
and not any(k == k_ for k_, _ in (sort or [])) and not any(k == k_ for k_, _ in (sort or []))
and k != enumerate_
and k != children and k != children
and not any(k == k_ for k_, _ in (hot or [])) and not any(k == k_ for k_, _ in (hot or []))
and k != notes and k != notes
@@ -2199,7 +2241,6 @@ def main(csv_paths, *,
if k not in (by or []) if k not in (by or [])
and not any(k == k_ for k_, _ in defines) and not any(k == k_ for k_, _ in defines)
and not any(k == k_ for k_, _ in (sort or [])) and not any(k == k_ for k_, _ in (sort or []))
and k != enumerate_
and k != children and k != children
and not any(k == k_ for k_, _ in (hot or [])) and not any(k == k_ for k_, _ in (hot or []))
and k != notes and k != notes
@@ -2215,7 +2256,6 @@ def main(csv_paths, *,
exprs=exprs, exprs=exprs,
defines=defines, defines=defines,
sort=sort, sort=sort,
enumerate=enumerate_,
children=children, children=children,
hot=hot, hot=hot,
notes=notes) notes=notes)
@@ -2246,8 +2286,7 @@ def main(csv_paths, *,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], Result, results, write_csv(args['output_json'], Result, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -2277,6 +2316,7 @@ def main(csv_paths, *,
by=by, by=by,
fields=fields, fields=fields,
sort=sort, sort=sort,
labels=labels,
depth=depth, depth=depth,
**args) **args)
@@ -2389,8 +2429,20 @@ if __name__ == "__main__":
'-i', '--enumerate', '-i', '--enumerate',
nargs='?', nargs='?',
const='i', const='i',
action='append',
help="Field to use for enumerating results. This will prevent " help="Field to use for enumerating results. This will prevent "
"result folding.") "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( parser.add_argument(
'-z', '--depth', '-z', '--depth',
nargs='?', nargs='?',
@@ -2402,6 +2454,7 @@ if __name__ == "__main__":
'-Z', '--children', '-Z', '--children',
nargs='?', nargs='?',
const='children', const='children',
action='append',
help="Field to use for recursive results. This expects a list " help="Field to use for recursive results. This expects a list "
"and really only works with JSON input.") "and really only works with JSON input.")
class AppendHot(argparse.Action): class AppendHot(argparse.Action):
@@ -2437,6 +2490,7 @@ if __name__ == "__main__":
'-N', '--notes', '-N', '--notes',
nargs='?', nargs='?',
const='notes', const='notes',
action='append',
help="Field to use for notes.") help="Field to use for notes.")
parser.add_argument( parser.add_argument(
'--no-header', '--no-header',

View File

@@ -841,6 +841,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -850,8 +853,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -895,7 +896,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -980,6 +983,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1290,8 +1303,7 @@ def main(obj_paths, *,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], CtxResult, results, write_csv(args['output_json'], CtxResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -1318,9 +1330,10 @@ def main(obj_paths, *,
# print table # print table
if not args.get('quiet'): if not args.get('quiet'):
table(CtxResult, results, diff_results, 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'], fields=fields if fields is not None else ['size'],
sort=sort, sort=sort,
labels=by if by is not None else ['function'],
depth=depth, depth=depth,
**args) **args)

View File

@@ -583,6 +583,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -592,8 +595,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -637,7 +638,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -722,6 +725,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1014,8 +1027,7 @@ def main(obj_paths, *,
fields=fields, fields=fields,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], DataResult, results, write_csv(args['output_json'], DataResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
**args) **args)

View File

@@ -945,6 +945,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -954,8 +957,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -999,7 +1000,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -1084,6 +1087,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1503,8 +1516,7 @@ def report(perf_paths, *,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], PerfResult, results, write_csv(args['output_json'], PerfResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -1539,12 +1551,13 @@ def report(perf_paths, *,
else: else:
# print table # print table
table(PerfResult, results, diff_results, 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 fields=fields if fields is not None
else ['cycles'] if not branches and not caches else ['cycles'] if not branches and not caches
else ['bmisses', 'branches'] if branches else ['bmisses', 'branches'] if branches
else ['cmisses', 'caches'], else ['cmisses', 'caches'],
sort=sort, sort=sort,
labels=by if by is not None else ['function'],
depth=depth, depth=depth,
**args) **args)

View File

@@ -915,6 +915,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -924,8 +927,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -969,7 +970,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -1054,6 +1057,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1502,8 +1515,7 @@ def report(paths, *,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], PerfBdResult, results, write_csv(args['output_json'], PerfBdResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -1539,10 +1551,11 @@ def report(paths, *,
else: else:
# print table # print table
table(PerfBdResult, results, diff_results, 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 fields=fields if fields is not None
else ['readed', 'proged', 'erased'], else ['readed', 'proged', 'erased'],
sort=sort, sort=sort,
labels=by if by is not None else ['function'],
depth=depth, depth=depth,
**args) **args)

View File

@@ -587,6 +587,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -596,8 +599,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -641,7 +642,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -726,6 +729,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1036,8 +1049,7 @@ def main(ci_paths,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], StackResult, results, write_csv(args['output_json'], StackResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -1064,9 +1076,10 @@ def main(ci_paths,
# print table # print table
if not args.get('quiet'): if not args.get('quiet'):
table(StackResult, results, diff_results, 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'], fields=fields if fields is not None else ['frame', 'limit'],
sort=sort, sort=sort,
labels=by if by is not None else ['function'],
depth=depth, depth=depth,
**args) **args)

View File

@@ -661,6 +661,9 @@ def table(Result, results, diff_results=None, *,
by=None, by=None,
fields=None, fields=None,
sort=None, sort=None,
labels=None,
depth=1,
hot=None,
diff=None, diff=None,
percent=None, percent=None,
all=False, all=False,
@@ -670,8 +673,6 @@ def table(Result, results, diff_results=None, *,
no_total=False, no_total=False,
small_table=False, small_table=False,
summary=False, summary=False,
depth=1,
hot=None,
**_): **_):
import builtins import builtins
all_, all = all, builtins.all all_, all = all, builtins.all
@@ -715,7 +716,7 @@ def table(Result, results, diff_results=None, *,
# header # header
if not no_header: if not no_header:
header = ['%s%s' % ( header = ['%s%s' % (
','.join(by), ','.join(labels if labels is not None else by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in 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 # entry helper
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
# prepend name
entry = [name] entry = [name]
# normal entry? # normal entry?
if ((compare is None or r == compare_r) if ((compare is None or r == compare_r)
and not percent and not percent
@@ -800,6 +803,7 @@ def table(Result, results, diff_results=None, *,
types[k].ratio( types[k].ratio(
getattr(r, k, None), getattr(r, k, None),
getattr(diff_r, k, None))))) getattr(diff_r, k, None)))))
# append any notes # append any notes
if hasattr(Result, '_notes') and r is not None: if hasattr(Result, '_notes') and r is not None:
notes = sorted(getattr(r, Result._notes)) 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) # and finally by name (diffs may be missing results)
n)) n))
for i, n in enumerate(names_): for i, name in enumerate(names_):
# find comparable results # find comparable results
r = table_.get(n) r = table_.get(name)
diff_r = diff_table_.get(n) 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 # build line
line = table_entry(n, r, diff_r) line = table_entry(label, r, diff_r)
# add prefixes # add prefixes
line = [x if isinstance(x, tuple) else (x, []) for x in line] 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) lines.append(line)
# recurse? # recurse?
if n in table_ and depth_ > 1: if name in table_ and depth_ > 1:
table_recurse( table_recurse(
getattr(r, Result._children), getattr(r, Result._children),
getattr(diff_r, Result._children, None) or [], getattr(diff_r, Result._children, None) or [],
@@ -1110,8 +1123,7 @@ def main(obj_paths, *,
depth=depth, depth=depth,
**args) **args)
if args.get('output_json'): if args.get('output_json'):
write_csv(args['output_json'], StructResult, results, write_csv(args['output_json'], StructResult, results, json=True,
json=True,
by=by, by=by,
fields=fields, fields=fields,
depth=depth, depth=depth,
@@ -1138,9 +1150,10 @@ def main(obj_paths, *,
# print table # print table
if not args.get('quiet'): if not args.get('quiet'):
table(StructResult, results, diff_results, 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'], fields=fields if fields is not None else ['size', 'align'],
sort=sort, sort=sort,
labels=by if by is not None else ['struct'],
depth=depth, depth=depth,
**args) **args)