scripts: csv.py: Added --list-computed to expose expr deps/types/etc
Less useful than --list-fields, but fun.
This shows more of the internal expr eval info: input fields + types,
output fields + types + folds, and a small dependency graph showing what
goes where:
$ ./scripts/csv.py --list-computed test.csv \
-bcase='%(case)s+%(m)s' \
-fsimtime='float(bench_simtime)/1.0e9' \
-fsimthroughput='float(n)/max(float(bench_simtime)/1.0e9,1.0e-9)'
i ? .--> case ? ?
suite ? |.-> simtime int sum
case ? -+|.> simthroughput int sum
SKIP_WARMUP ? |||
FILE_SIZE ? |||
SEED ? |||
...
m ? -'||
n int ---+
bench_reads ? ||
bench_progs ? ||
bench_erases ? ||
bench_readed ? ||
bench_progged ? ||
bench_erased ? ||
bench_simtime int ---'
Maybe I was just itching to write another ascii-art renderer.
This commit is contained in:
+160
-10
@@ -1632,12 +1632,12 @@ def compile(fields_, results,
|
|||||||
r_[k] = t(r[k]) if k in r else t()
|
r_[k] = t(r[k]) if k in r else t()
|
||||||
|
|
||||||
r__ = r_.copy()
|
r__ = r_.copy()
|
||||||
# evaluate exprs
|
|
||||||
for k, expr in exprs.items():
|
|
||||||
r__[k] = expr.eval(r_, _state)
|
|
||||||
# evaluate mods
|
# evaluate mods
|
||||||
for k, m in mods.items():
|
for k, m in mods.items():
|
||||||
r__[k] = punescape(m, r_)
|
r__[k] = punescape(m, r_)
|
||||||
|
# evaluate exprs
|
||||||
|
for k, expr in exprs.items():
|
||||||
|
r__[k] = expr.eval(r_, _state)
|
||||||
|
|
||||||
# return result
|
# return result
|
||||||
return cls.__mro__[1].__new__(cls, **(
|
return cls.__mro__[1].__new__(cls, **(
|
||||||
@@ -1699,10 +1699,13 @@ def compile(fields_, results,
|
|||||||
__new__=__new__,
|
__new__=__new__,
|
||||||
__add__=__add__,
|
__add__=__add__,
|
||||||
__getattribute__=__getattribute__,
|
__getattribute__=__getattribute__,
|
||||||
|
_fields_ = fields_,
|
||||||
|
_types_ = types__,
|
||||||
_by=by,
|
_by=by,
|
||||||
_fields=fields,
|
_fields=fields,
|
||||||
_sort=fields,
|
_sort=fields,
|
||||||
_types={k: t for k, (_, t) in folds___.items()},
|
_types={k: t for k, (_, t) in folds___.items()},
|
||||||
|
_folds={k: f for k, (f, _) in folds___.items()},
|
||||||
_mods=mods,
|
_mods=mods,
|
||||||
_exprs=exprs,
|
_exprs=exprs,
|
||||||
**{'_z': z} if z is not None else {},
|
**{'_z': z} if z is not None else {},
|
||||||
@@ -2369,21 +2372,160 @@ def list_fields(csv_paths, **args):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# find widths
|
# find best name for types
|
||||||
w = [0]
|
types__ = []
|
||||||
for k in fields_:
|
|
||||||
w[0] = max(w[0], len(k))
|
|
||||||
|
|
||||||
for k in fields_:
|
for k in fields_:
|
||||||
if k in types_:
|
if k in types_:
|
||||||
t = types_[k].__name__
|
t = types_[k].__name__
|
||||||
if t.startswith('Csv'):
|
if t.startswith('Csv'):
|
||||||
t = t[len('Csv'):]
|
t = t[len('Csv'):]
|
||||||
t = t.lower()
|
types__.append(t.lower())
|
||||||
else:
|
else:
|
||||||
t = '?'
|
types__.append('?')
|
||||||
|
|
||||||
|
# find widths
|
||||||
|
w = [0]
|
||||||
|
for k in fields_:
|
||||||
|
w[0] = max(w[0], len(k))
|
||||||
|
|
||||||
|
for k, t in zip(fields_, types__):
|
||||||
print('%-*s %s' % (w[0], k, t))
|
print('%-*s %s' % (w[0], k, t))
|
||||||
|
|
||||||
|
def list_computed(Result, **args):
|
||||||
|
# figure out input fields and types, these are stashed in the
|
||||||
|
# compiled Result type for this sort of introspection
|
||||||
|
fields_ = Result._fields_
|
||||||
|
types_ = Result._types_
|
||||||
|
|
||||||
|
# find best name for types
|
||||||
|
types__ = []
|
||||||
|
for k in fields_:
|
||||||
|
if k in types_:
|
||||||
|
t = types_[k].__name__
|
||||||
|
if t.startswith('Csv'):
|
||||||
|
t = t[len('Csv'):]
|
||||||
|
types__.append(t.lower())
|
||||||
|
else:
|
||||||
|
types__.append('?')
|
||||||
|
|
||||||
|
# figure out output fields
|
||||||
|
fields = list(co.OrderedDict.fromkeys(it.chain(
|
||||||
|
Result._by,
|
||||||
|
Result._fields,
|
||||||
|
(Result._z,) if hasattr(Result, '_z') else (),
|
||||||
|
(Result._children,) if hasattr(Result, '_children') else (),
|
||||||
|
(Result._notes,) if hasattr(Result, '_notes') else ())).keys())
|
||||||
|
|
||||||
|
# figure out deps
|
||||||
|
deps = []
|
||||||
|
for k in fields:
|
||||||
|
deps_ = set()
|
||||||
|
if k in Result._exprs:
|
||||||
|
deps_.update(Result._exprs[k].fields())
|
||||||
|
elif k in Result._mods:
|
||||||
|
# bit of a hack, but we don't usually know mod deps
|
||||||
|
# until eval time
|
||||||
|
deps_.update(re.findall('(?<!%)%\(([^)]*)\)', Result._mods[k]))
|
||||||
|
else:
|
||||||
|
# by default, dep is the field itself
|
||||||
|
deps_ = {k}
|
||||||
|
# ignore non-existant deps
|
||||||
|
deps_ = {d for d in deps_ if d in fields_}
|
||||||
|
deps.append(deps_)
|
||||||
|
|
||||||
|
# find best name for types
|
||||||
|
types = []
|
||||||
|
for k in fields:
|
||||||
|
# special cases for z/children/notes
|
||||||
|
if hasattr(Result, '_z') and k == Result._z:
|
||||||
|
types.append('z')
|
||||||
|
elif hasattr(Result, '_children') and k == Result._children:
|
||||||
|
types.append('children')
|
||||||
|
elif hasattr(Result, '_notes') and k == Result._notes:
|
||||||
|
types.append('notes')
|
||||||
|
# figure out name
|
||||||
|
elif k in Result._types:
|
||||||
|
t = Result._types[k].__name__
|
||||||
|
if t.startswith('Csv'):
|
||||||
|
t = t[len('Csv'):]
|
||||||
|
types.append(t.lower())
|
||||||
|
else:
|
||||||
|
types.append('?')
|
||||||
|
|
||||||
|
# find best name for folds
|
||||||
|
folds = []
|
||||||
|
for k in fields:
|
||||||
|
# special cases for children/notes
|
||||||
|
if hasattr(Result, '_z') and k == Result._z:
|
||||||
|
folds.append('z')
|
||||||
|
elif hasattr(Result, '_children') and k == Result._children:
|
||||||
|
folds.append('children')
|
||||||
|
elif hasattr(Result, '_notes') and k == Result._notes:
|
||||||
|
folds.append('notes')
|
||||||
|
# figure out name
|
||||||
|
elif k in Result._folds:
|
||||||
|
t = Result._folds[k].__class__.__name__
|
||||||
|
if t.startswith('Csv'):
|
||||||
|
t = t[len('Csv'):]
|
||||||
|
folds.append(t.lower())
|
||||||
|
else:
|
||||||
|
folds.append('?')
|
||||||
|
|
||||||
|
# build dep grid
|
||||||
|
dwidth = 2 + sum(1 for d in deps if d)
|
||||||
|
dheight = max(len(fields_), len(fields))
|
||||||
|
dgrid = [' ' for _ in range(dwidth*dheight)]
|
||||||
|
|
||||||
|
for i, (k, d) in enumerate((k, d) for k, d in zip(fields, deps) if d):
|
||||||
|
# find starting ys
|
||||||
|
a = []
|
||||||
|
for y, k_ in enumerate(fields_):
|
||||||
|
if k_ in d:
|
||||||
|
a.append(y)
|
||||||
|
# find ending y
|
||||||
|
b = i
|
||||||
|
for y, k_ in enumerate(fields):
|
||||||
|
if k_ == k:
|
||||||
|
b = y
|
||||||
|
# draw start lines
|
||||||
|
for y in a:
|
||||||
|
for x in range(0, 1+i):
|
||||||
|
dgrid[y*dwidth + x] = '-'
|
||||||
|
# draw end lines
|
||||||
|
for x in range(1+i+1, dwidth):
|
||||||
|
dgrid[b*dwidth + x] = '>' if x == dwidth-1 else '-'
|
||||||
|
# draw connections
|
||||||
|
min_ = min(min(a), b)
|
||||||
|
max_ = max(max(a), b)
|
||||||
|
for y in range(min_, max_+1):
|
||||||
|
dgrid[y*dwidth + 1+i] = (
|
||||||
|
'-' if min_ == max_
|
||||||
|
else '+' if y in a and y == b
|
||||||
|
else '.' if y == min_
|
||||||
|
else '\'' if y == max_
|
||||||
|
else '+' if y in a or y == b
|
||||||
|
else '|')
|
||||||
|
|
||||||
|
# find widths
|
||||||
|
w = [0, 0, 0, 0]
|
||||||
|
for k_, t_, k, t in it.zip_longest(
|
||||||
|
fields_, types__, fields, types):
|
||||||
|
w[0] = max(w[0], len(k_ or ''))
|
||||||
|
w[1] = max(w[1], len(t_ or ''))
|
||||||
|
w[2] = max(w[2], len(k or ''))
|
||||||
|
w[3] = max(w[3], len(t or ''))
|
||||||
|
|
||||||
|
for i, (k_, t_, k, t, f) in enumerate(
|
||||||
|
it.zip_longest(
|
||||||
|
fields_, types__, fields, types, folds)):
|
||||||
|
print('%-*s %-*s %s %-*s %-*s %s' % (
|
||||||
|
w[0], k_ or '',
|
||||||
|
w[1], t_ or '',
|
||||||
|
''.join(dgrid[i*dwidth:i*dwidth+dwidth]),
|
||||||
|
w[2], k or '',
|
||||||
|
w[3], t or '',
|
||||||
|
f or ''))
|
||||||
|
|
||||||
|
|
||||||
# entry point
|
# entry point
|
||||||
def main(csv_paths, *,
|
def main(csv_paths, *,
|
||||||
@@ -2553,6 +2695,10 @@ def main(csv_paths, *,
|
|||||||
hot=hot,
|
hot=hot,
|
||||||
notes=notes)
|
notes=notes)
|
||||||
|
|
||||||
|
# list computed?
|
||||||
|
if args.get('list_computed'):
|
||||||
|
return list_computed(Result, **args)
|
||||||
|
|
||||||
# homogenize
|
# homogenize
|
||||||
results = homogenize(Result, results,
|
results = homogenize(Result, results,
|
||||||
defines=defines,
|
defines=defines,
|
||||||
@@ -2651,6 +2797,10 @@ if __name__ == "__main__":
|
|||||||
'--list-fields',
|
'--list-fields',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help="List fields and inferred types before processing.")
|
help="List fields and inferred types before processing.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--list-computed',
|
||||||
|
action='store_true',
|
||||||
|
help="List computed fields and expression dependencies.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-q', '--quiet',
|
'-q', '--quiet',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
Reference in New Issue
Block a user