scripts: Adopted double-indent on multiline expressions

This matches the style used in C, which is good for consistency:

  a_really_long_function_name(
          double_indent_after_first_newline(
              single_indent_nested_newlines))

We were already doing this for multiline control-flow statements, simply
because I'm not sure how else you could indent this without making
things really confusing:

  if a_really_long_function_name(
          double_indent_after_first_newline(
              single_indent_nested_newlines)):
      do_the_thing()

This was the only real difference style-wise between the Python code and
C code, so now both should be following roughly the same style (80 cols,
double-indent multiline exprs, prefix multiline binary ops, etc).
This commit is contained in:
Christopher Haster
2024-11-06 15:31:17 -06:00
parent 48c2e7784b
commit 007ac97bec
34 changed files with 6290 additions and 6109 deletions
+10 -10
View File
@@ -108,8 +108,7 @@ def main(csv_paths, output, *,
# if by not specified, guess it's anything not in
# iter/size/fields/renames/defines
if by is None:
by = [
k for k in fields_
by = [k for k in fields_
if k != iter
and k != size
and k not in (fields or [])
@@ -119,8 +118,7 @@ def main(csv_paths, output, *,
# if fields not specified, guess it's anything not in
# by/iter/size/renames/defines
if fields is None:
fields = [
k for k in fields_
fields = [k for k in fields_
if k not in (by or [])
and k != iter
and k != size
@@ -214,11 +212,12 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Group by this field. Can rename fields with new_name=old_name.")
help="Group by this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-m', '--meas',
help="Optional name of measurement name field. If provided, the name "
"will be modified with +amor or +per.")
help="Optional name of measurement name field. If provided, the "
"name will be modified with +amor or +per.")
parser.add_argument(
'-i', '--iter',
required=True,
@@ -236,7 +235,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Field to amortize. Can rename fields with new_name=old_name.")
help="Field to amortize. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-D', '--define',
dest='defines',
@@ -246,8 +246,8 @@ if __name__ == "__main__":
k.strip(),
{v.strip() for v in vs.split(',')})
)(*x.split('=', 1)),
help="Only include results where this field is this value. May include "
"comma-separated options.")
help="Only include results where this field is this value. May "
"include comma-separated options.")
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))
+11 -12
View File
@@ -128,8 +128,7 @@ def main(csv_paths, output, *,
# if by not specified, guess it's anything not in
# seeds/fields/renames/defines
if by is None:
by = [
k for k in fields_
by = [k for k in fields_
if k not in (seeds or [])
and k not in (fields or [])
and not any(k == old_k for _, old_k in renames)
@@ -138,8 +137,7 @@ def main(csv_paths, output, *,
# if fields not specified, guess it's anything not in
# by/seeds/renames/defines
if fields is None:
fields = [
k for k in fields_
fields = [k for k in fields_
if k not in (by or [])
and k not in (seeds or [])
and not any(k == old_k for _, old_k in renames)
@@ -174,8 +172,7 @@ def main(csv_paths, output, *,
meas__ = r[meas]
def append(meas_, f_):
avgs.append(
{k: v for k, v in zip(by, key)}
avgs.append({k: v for k, v in zip(by, key)}
| {f: f_(vs_) for f, vs_ in vs.items()}
| ({} if meas is None
else {meas: meas_} if meas__ is None
@@ -267,11 +264,12 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Group by this field. Can rename fields with new_name=old_name.")
help="Group by this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-m', '--meas',
help="Optional name of measurement name field. If provided, the name "
"will be modified with +amor or +per.")
help="Optional name of measurement name field. If provided, the "
"name will be modified with +amor or +per.")
parser.add_argument(
'-s', '--seed',
dest='seeds',
@@ -294,7 +292,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Field to amortize. Can rename fields with new_name=old_name.")
help="Field to amortize. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-D', '--define',
dest='defines',
@@ -304,8 +303,8 @@ if __name__ == "__main__":
k.strip(),
{v.strip() for v in vs.split(',')})
)(*x.split('=', 1)),
help="Only include results where this field is this value. May include "
"comma-separated options.")
help="Only include results where this field is this value. May "
"include comma-separated options.")
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))
+81 -74
View File
@@ -192,7 +192,8 @@ class BenchSuite:
case_linenos, case_linenos[1:],
fillvalue=(float('inf'), None)):
code_lineno = min(
(l for l in code_linenos if l >= lineno and l < nlineno),
(l for l in code_linenos
if l >= lineno and l < nlineno),
default=None)
cases[name]['lineno'] = lineno
cases[name]['code_lineno'] = code_lineno
@@ -221,7 +222,8 @@ class BenchSuite:
self.cases = []
for name, case in cases.items():
self.cases.append(BenchCase(config={
self.cases.append(BenchCase(
config={
'name': name,
'path': path + (':%d' % case['lineno']
if 'lineno' in case else ''),
@@ -374,23 +376,21 @@ def compile(bench_paths, **args):
for k, vs in sorted(permutation.items()):
f.writeln('intmax_t __bench__%s__%s__%d('
'__attribute__((unused)) void *data, '
'size_t i) {'
% (case.name, k, i))
'size_t i) {' % (
case.name, k, i))
j = 0
for v in vs:
# generate range
if isinstance(v, range):
f.writeln(
4*' '+'if (i < %d) '
'return (i-%d)*%d + %d;'
% (j+len(v), j, v.step, v.start))
f.writeln(4*' '+'if (i < %d) '
'return (i-%d)*%d + %d;' % (
j+len(v), j, v.step, v.start))
j += len(v)
# translate index to define
else:
f.writeln(
4*' '+'if (i == %d) '
'return %s;'
% (j, v))
f.writeln(4*' '+'if (i == %d) '
'return %s;' % (
j, v))
j += 1;
f.writeln(4*' '+'__builtin_unreachable();')
@@ -399,8 +399,8 @@ def compile(bench_paths, **args):
# create case if function
if suite.if_ or case.if_:
f.writeln('bool __bench__%s__if(void) {'
% (case.name))
f.writeln('bool __bench__%s__if(void) {' % (
case.name))
for if_ in it.chain(suite.if_, case.if_):
f.writeln(4*' '+'if (!(%s)) return false;' % (
'true' if if_ is True
@@ -412,16 +412,17 @@ def compile(bench_paths, **args):
# create case run function
f.writeln('void __bench__%s__run('
'__attribute__((unused)) struct lfs_config *CFG) {'
% (case.name))
'__attribute__((unused)) '
'struct lfs_config *CFG) {' % (
case.name))
f.writeln(4*' '+'// bench case %s' % case.name)
if case.code_lineno is not None:
f.writeln(4*' '+'#line %d "%s"'
% (case.code_lineno, suite.path))
f.writeln(4*' '+'#line %d "%s"' % (
case.code_lineno, suite.path))
f.write(case.code)
if case.code_lineno is not None:
f.writeln(4*' '+'#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln(4*' '+'#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln('}')
f.writeln()
@@ -441,19 +442,19 @@ def compile(bench_paths, **args):
# write any suite defines
if suite.defines:
for define in sorted(suite.defines):
f.writeln('__attribute__((weak)) intmax_t %s;'
% define)
f.writeln('__attribute__((weak)) intmax_t %s;' % (
define))
f.writeln()
# write any suite code
if suite.code is not None and suite.in_ is None:
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (suite.code_lineno, suite.path))
f.writeln('#line %d "%s"' % (
suite.code_lineno, suite.path))
f.write(suite.code)
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln('#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln()
# create case functions
@@ -464,15 +465,15 @@ def compile(bench_paths, **args):
for i, permutation in enumerate(case.permutations):
for k, vs in sorted(permutation.items()):
f.writeln('extern intmax_t __bench__%s__%s__%d('
'void *data, size_t i);'
% (case.name, k, i))
'void *data, size_t i);' % (
case.name, k, i))
if suite.if_ or case.if_:
f.writeln('extern bool __bench__%s__if('
'void);'
% (case.name))
'void);' % (
case.name))
f.writeln('extern void __bench__%s__run('
'struct lfs_config *CFG);'
% (case.name))
'struct lfs_config *CFG);' % (
case.name))
f.writeln()
# write any ifdef epilogues
@@ -482,12 +483,12 @@ def compile(bench_paths, **args):
f.writeln()
# create suite struct
f.writeln('const struct bench_suite __bench__%s__suite = {'
% suite.name)
f.writeln('const struct bench_suite __bench__%s__suite = {' % (
suite.name))
f.writeln(4*' '+'.name = "%s",' % suite.name)
f.writeln(4*' '+'.path = "%s",' % suite.path)
f.writeln(4*' '+'.flags = %s,'
% (' | '.join(filter(None, [
f.writeln(4*' '+'.flags = %s,' % (
' | '.join(filter(None, [
'BENCH_INTERNAL' if suite.internal else None]))
or 0))
for ifdef in suite.ifdef:
@@ -496,8 +497,8 @@ def compile(bench_paths, **args):
if suite.defines:
f.writeln(4*' '+'.defines = (const bench_define_t[]){')
for k in sorted(suite.defines):
f.writeln(8*' '+'{"%s", &%s, NULL, NULL, 0},'
% (k, k))
f.writeln(8*' '+'{"%s", &%s, NULL, NULL, 0},' % (
k, k))
f.writeln(4*' '+'},')
f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
for ifdef in suite.ifdef:
@@ -509,9 +510,10 @@ def compile(bench_paths, **args):
f.writeln(8*' '+'{')
f.writeln(12*' '+'.name = "%s",' % case.name)
f.writeln(12*' '+'.path = "%s",' % case.path)
f.writeln(12*' '+'.flags = %s,'
% (' | '.join(filter(None, [
'BENCH_INTERNAL' if suite.internal else None]))
f.writeln(12*' '+'.flags = %s,' % (
' | '.join(filter(None, [
'BENCH_INTERNAL' if suite.internal
else None]))
or 0))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#ifdef %s' % ifdef)
@@ -519,15 +521,16 @@ def compile(bench_paths, **args):
if case.defines:
f.writeln(12*' '+'.defines'
' = (const bench_define_t*)'
'(const bench_define_t[][%d]){'
% (len(suite.defines)))
'(const bench_define_t[][%d]){' % (
len(suite.defines)))
for i, permutation in enumerate(case.permutations):
f.writeln(16*' '+'{')
for k, vs in sorted(permutation.items()):
f.writeln(20*' '+'[%d] = {'
'"%s", &%s, '
'__bench__%s__%s__%d, NULL, %d},'
% (sorted(suite.defines).index(k),
'__bench__%s__%s__%d, '
'NULL, %d},' % (
sorted(suite.defines).index(k),
k, k, case.name, k, i,
sum(len(v)
if isinstance(v, range)
@@ -535,13 +538,13 @@ def compile(bench_paths, **args):
for v in vs)))
f.writeln(16*' '+'},')
f.writeln(12*' '+'},')
f.writeln(12*' '+'.permutations = %d,'
% len(case.permutations))
f.writeln(12*' '+'.permutations = %d,' % (
len(case.permutations)))
if suite.if_ or case.if_:
f.writeln(12*' '+'.if_ = __bench__%s__if,'
% (case.name))
f.writeln(12*' '+'.run = __bench__%s__run,'
% (case.name))
f.writeln(12*' '+'.if_ = __bench__%s__if,' % (
case.name))
f.writeln(12*' '+'.run = __bench__%s__run,' % (
case.name))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#endif')
f.writeln(8*' '+'},')
@@ -570,8 +573,8 @@ def compile(bench_paths, **args):
for define in case.defines})
if defines:
for define in sorted(defines):
f.writeln('__attribute__((weak)) intmax_t %s;'
% define)
f.writeln('__attribute__((weak)) intmax_t %s;' % (
define))
f.writeln()
# write any internal benches
@@ -585,12 +588,12 @@ def compile(bench_paths, **args):
# any suite code
if suite.isin(args['source']):
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (suite.code_lineno, suite.path))
f.writeln('#line %d "%s"' % (
suite.code_lineno, suite.path))
f.write(suite.code)
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln('#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln()
# any case functions
@@ -611,11 +614,12 @@ def compile(bench_paths, **args):
# will be linked
for suite in suites:
f.writeln('extern const struct bench_suite '
'__bench__%s__suite;' % suite.name)
'__bench__%s__suite;' % (
suite.name))
f.writeln()
f.writeln('__attribute__((weak))')
f.writeln('const struct bench_suite *const bench_suites[] = {');
f.writeln('const struct bench_suite *const bench_suites[] = {')
for suite in suites:
f.writeln(4*' '+'&__bench__%s__suite,' % suite.name)
if len(suites) == 0:
@@ -768,8 +772,7 @@ def find_perms(runner, bench_ids=[], **args):
expected_suite_perms.get(suite, 0)
+ expected_case_perms.get(case, 0))
return (
case_suites,
return (case_suites,
expected_suite_perms,
expected_case_perms,
expected_perms,
@@ -1246,8 +1249,7 @@ def run_stage(name, runner, bench_ids, stdout_, trace_, output_, **args):
for r in runners:
r.join()
return (
expected_perms,
return (expected_perms,
passed_perms,
failed_perms,
readed,
@@ -1381,7 +1383,8 @@ def run(runner, bench_ids=[], **args):
'\x1b[01;31m' if args['color'] else '',
'\x1b[m' if args['color'] else '',
failure.id,
' (%s)' % ', '.join('%s=%s' % (k,v) for k,v in defines.items())
' (%s)' % ', '.join('%s=%s' % (k,v)
for k,v in defines.items())
if defines else ''))
if failure.stdout:
@@ -1495,7 +1498,8 @@ if __name__ == "__main__":
'-R', '--runner',
type=lambda x: x.split(),
default=RUNNER_PATH,
help="Bench runner to use for benching. Defaults to %r." % RUNNER_PATH)
help="Bench runner to use for benching. Defaults to "
"%r." % RUNNER_PATH)
bench_parser.add_argument(
'-Y', '--summary',
action='store_true',
@@ -1557,7 +1561,8 @@ if __name__ == "__main__":
help="Sample trace output at this frequency in hz.")
bench_parser.add_argument(
'-O', '--stdout',
help="Direct stdout to this file. Note stderr is already merged here.")
help="Direct stdout to this file. Note stderr is already merged "
"here.")
bench_parser.add_argument(
'-o', '--output',
help="CSV file to store results.")
@@ -1575,7 +1580,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Number of parallel runners to run. 0 runs one runner per core.")
help="Number of parallel runners to run. 0 runs one runner per "
"core.")
bench_parser.add_argument(
'-k', '--keep-going',
action='store_true',
@@ -1644,12 +1650,12 @@ if __name__ == "__main__":
"Defaults to %r." % VALGRIND_PATH)
bench_parser.add_argument(
'-p', '--perf',
help="Run under Linux's perf to sample performance counters, writing "
"samples to this file.")
help="Run under Linux's perf to sample performance counters, "
"writing samples to this file.")
bench_parser.add_argument(
'--perf-freq',
help="perf sampling frequency. This is passed directly to the perf "
"script.")
help="perf sampling frequency. This is passed directly to the "
"perf script.")
bench_parser.add_argument(
'--perf-period',
help="perf sampling period. This is passed directly to the perf "
@@ -1662,12 +1668,13 @@ if __name__ == "__main__":
'--perf-script',
type=lambda x: x.split(),
default=PERF_SCRIPT,
help="Path to the perf script to use. Defaults to %r." % PERF_SCRIPT)
help="Path to the perf script to use. Defaults to "
"%r." % PERF_SCRIPT)
bench_parser.add_argument(
'--perf-path',
type=lambda x: x.split(),
help="Path to the perf executable, may include flags. This is passed "
"directly to the perf script")
help="Path to the perf executable, may include flags. This is "
"passed directly to the perf script")
# compilation flags
comp_parser = parser.add_argument_group('compilation options')
+6 -4
View File
@@ -21,6 +21,7 @@ import shutil
import subprocess
import tempfile
GIT_PATH = ['git']
@@ -79,7 +80,8 @@ def changefile(from_prefix, to_prefix, from_path, to_path, *,
# Summary
print('%s: %d replacements' % (
'%s -> %s' % (from_path, to_path) if not to_path_temp else from_path,
'%s -> %s' % (from_path, to_path) if not to_path_temp
else from_path,
count))
def main(from_prefix, to_prefix, paths=[], *,
@@ -130,9 +132,9 @@ if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Change prefixes in files/filenames. Useful for creating "
"different versions of a codebase that don't conflict at compile "
"time.",
description="Change prefixes in files/filenames. Useful for "
"creating different versions of a codebase that don't "
"conflict at compile time.",
allow_abbrev=False)
parser.add_argument(
'from_prefix',
+22 -17
View File
@@ -140,9 +140,9 @@ def collect(obj_paths, *,
everything=False,
**args):
size_pattern = re.compile(
'^(?P<size>[0-9a-fA-F]+)' +
' (?P<type>[%s])' % re.escape(nm_types) +
' (?P<func>.+?)$')
'^(?P<size>[0-9a-fA-F]+)'
+ ' (?P<type>[%s])' % re.escape(nm_types)
+ ' (?P<func>.+?)$')
line_pattern = re.compile(
'^\s+(?P<no>[0-9]+)'
'(?:\s+(?P<dir>[0-9]+))?'
@@ -288,8 +288,7 @@ def collect(obj_paths, *,
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(file) == os.path.abspath(s)
if not any(os.path.abspath(file) == os.path.abspath(s)
for s in sources):
continue
else:
@@ -386,7 +385,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -397,9 +397,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -407,8 +410,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -566,14 +568,16 @@ def main(obj_paths, *,
writer = csv.DictWriter(f,
(by if by is not None else CodeResult._by)
+ [k for k in (
fields if fields is not None else CodeResult._fields)])
fields if fields is not None
else CodeResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else CodeResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else CodeResult._fields)})
fields if fields is not None
else CodeResult._fields)})
# find previous results?
if args.get('diff'):
@@ -692,8 +696,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -701,8 +705,9 @@ if __name__ == "__main__":
parser.add_argument(
'--nm-types',
default=NM_TYPES,
help="Type of symbols to report, this uses the same single-character "
"type-names emitted by nm. Defaults to %r." % NM_TYPES)
help="Type of symbols to report, this uses the same "
"single-character type-names emitted by nm. Defaults to "
"%r." % NM_TYPES)
parser.add_argument(
'--nm-path',
type=lambda x: x.split(),
+21 -17
View File
@@ -22,6 +22,7 @@ import re
import shlex
import subprocess as sp
# TODO use explode_asserts to avoid counting assert branches?
# TODO use dwarf=info to find functions for inline functions?
@@ -243,8 +244,7 @@ def collect(gcda_paths, *,
for file in data['files']:
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(file['file']) == os.path.abspath(s)
if not any(os.path.abspath(file['file']) == os.path.abspath(s)
for s in sources):
continue
else:
@@ -374,7 +374,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -385,9 +386,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -395,8 +399,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -639,14 +642,16 @@ def main(gcda_paths, *,
writer = csv.DictWriter(f,
(by if by is not None else CovResult._by)
+ [k for k in (
fields if fields is not None else CovResult._fields)])
fields if fields is not None
else CovResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else CovResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else CovResult._fields)})
fields if fields is not None
else CovResult._fields)})
# find previous results?
if args.get('diff'):
@@ -666,8 +671,7 @@ def main(gcda_paths, *,
diff_results.append(CovResult(
**{k: r[k] for k in CovResult._by
if k in r and r[k].strip()},
**{k: r[k]
for k in CovResult._fields
**{k: r[k] for k in CovResult._fields
if k in r and r[k].strip()}))
except TypeError:
pass
@@ -675,8 +679,7 @@ def main(gcda_paths, *,
pass
# fold
diff_results = fold(CovResult, diff_results,
by=by, defines=defines)
diff_results = fold(CovResult, diff_results, by=by, defines=defines)
# print table
if not args.get('quiet'):
@@ -784,8 +787,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -815,7 +818,8 @@ if __name__ == "__main__":
'-W', '--width',
type=lambda x: int(x, 0),
default=80,
help="Assume source is styled with this many columns. Defaults to 80.")
help="Assume source is styled with this many columns. Defaults "
"to 80.")
parser.add_argument(
'--color',
choices=['never', 'always', 'auto'],
+1
View File
@@ -57,6 +57,7 @@ def main(paths, **args):
else:
print('%08x' % crc)
if __name__ == "__main__":
import argparse
import sys
+22 -17
View File
@@ -140,9 +140,9 @@ def collect(obj_paths, *,
everything=False,
**args):
size_pattern = re.compile(
'^(?P<size>[0-9a-fA-F]+)' +
' (?P<type>[%s])' % re.escape(nm_types) +
' (?P<func>.+?)$')
'^(?P<size>[0-9a-fA-F]+)'
+ ' (?P<type>[%s])' % re.escape(nm_types)
+ ' (?P<func>.+?)$')
line_pattern = re.compile(
'^\s+(?P<no>[0-9]+)'
'(?:\s+(?P<dir>[0-9]+))?'
@@ -288,8 +288,7 @@ def collect(obj_paths, *,
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(file) == os.path.abspath(s)
if not any(os.path.abspath(file) == os.path.abspath(s)
for s in sources):
continue
else:
@@ -386,7 +385,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -397,9 +397,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -407,8 +410,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -563,14 +565,16 @@ def main(obj_paths, *,
writer = csv.DictWriter(f,
(by if by is not None else DataResult._by)
+ [k for k in (
fields if fields is not None else DataResult._fields)])
fields if fields is not None
else DataResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else DataResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else DataResult._fields)})
fields if fields is not None
else DataResult._fields)})
# find previous results?
if args.get('diff'):
@@ -689,8 +693,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -698,8 +702,9 @@ if __name__ == "__main__":
parser.add_argument(
'--nm-types',
default=NM_TYPES,
help="Type of symbols to report, this uses the same single-character "
"type-names emitted by nm. Defaults to %r." % NM_TYPES)
help="Type of symbols to report, this uses the same "
"single-character type-names emitted by nm. Defaults to "
"%r." % NM_TYPES)
parser.add_argument(
'--nm-path',
type=lambda x: x.split(),
+3 -1
View File
@@ -121,7 +121,8 @@ def main(disk, block=None, *,
size[1] - size[0] if isinstance(size, tuple) and len(size) > 1
else size[0] if isinstance(size, tuple)
else size if size is not None
else off[1] - off[0] if isinstance(off, tuple) and len(off) > 1
else off[1] - off[0]
if isinstance(off, tuple) and len(off) > 1
else block_size)
# read the block
@@ -143,6 +144,7 @@ def main(disk, block=None, *,
for o, line in enumerate(xxd(data)):
print('%08x: %s' % ((off or 0) + 16*o, line))
if __name__ == "__main__":
import argparse
import sys
+21 -12
View File
@@ -621,7 +621,8 @@ class Rbyd:
if len(blocks) > 1:
# fetch all blocks
rbyds = [cls.fetch(f, block_size, block, trunk) for block in blocks]
rbyds = [cls.fetch(f, block_size, block, trunk)
for block in blocks]
# determine most recent revision
i = 0
for i_, rbyd in enumerate(rbyds):
@@ -634,7 +635,8 @@ class Rbyd:
i = i_
# keep track of the other blocks
rbyd = rbyds[i]
rbyd.redund_blocks = [rbyds[(i+1+j) % len(rbyds)].block
rbyd.redund_blocks = [
rbyds[(i+1+j) % len(rbyds)].block
for j in range(len(rbyds)-1)]
return rbyd
else:
@@ -789,7 +791,9 @@ class Rbyd:
done = not tag_ or (rid_, tag_) < (rid, tag)
return done, rid_, tag_, w_, j, d, self.data[j+d:j+d+jump], path
return (done, rid_, tag_, w_, j, d,
self.data[j+d:j+d+jump],
path)
def __bool__(self):
return bool(self.trunk)
@@ -884,7 +888,8 @@ class Rbyd:
if done:
return True, -1, 0, None
mdir = next(((tag, j, d, data)
mdir = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1040,7 +1045,8 @@ def main(disk, mroots=None, *,
off_window=off_window,
# scale if we're printing with dots or braille
width=2*width_ if braille else width_,
height=max(1,
height=max(
1,
4*height_ if braille
else 2*height_ if dots
else height_))
@@ -1129,7 +1135,8 @@ def main(disk, mroots=None, *,
# mark mdir in our bmap
for block in mdir.blocks:
bmap.mdir(block,
mdir.eoff if args.get('in_use') else block_size)
mdir.eoff if args.get('in_use')
else block_size)
mdirs_ += 1
# find any file btrees in our mdir
@@ -1190,7 +1197,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1299,7 +1307,8 @@ def main(disk, mroots=None, *,
bptr__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
bptr__ = next(((tag, j, d, data)
bptr__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag & 0xfff == TAG_BLOCK),
None)
@@ -1418,8 +1427,8 @@ if __name__ == "__main__":
parser.add_argument(
'-⣿', '--braille',
action='store_true',
help="Use 2x4 unicode braille characters. Note that braille characters "
"sometimes suffer from inconsistent widths.")
help="Use 2x4 unicode braille characters. Note that braille "
"characters sometimes suffer from inconsistent widths.")
parser.add_argument(
'--chars',
help="Characters to use for mdir, btree, data, unused blocks.")
@@ -1445,8 +1454,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Show this many lines of history. 0 uses the terminal height. "
"Defaults to 5.")
help="Show this many lines of history. 0 uses the terminal "
"height. Defaults to 5.")
parser.add_argument(
'-U', '--hilbert',
action='store_true',
+13 -6
View File
@@ -289,7 +289,8 @@ class Rbyd:
if len(blocks) > 1:
# fetch all blocks
rbyds = [cls.fetch(f, block_size, block, trunk) for block in blocks]
rbyds = [cls.fetch(f, block_size, block, trunk)
for block in blocks]
# determine most recent revision
i = 0
for i_, rbyd in enumerate(rbyds):
@@ -302,7 +303,8 @@ class Rbyd:
i = i_
# keep track of the other blocks
rbyd = rbyds[i]
rbyd.redund_blocks = [rbyds[(i+1+j) % len(rbyds)].block
rbyd.redund_blocks = [
rbyds[(i+1+j) % len(rbyds)].block
for j in range(len(rbyds)-1)]
return rbyd
else:
@@ -457,7 +459,9 @@ class Rbyd:
done = not tag_ or (rid_, tag_) < (rid, tag)
return done, rid_, tag_, w_, j, d, self.data[j+d:j+d+jump], path
return (done, rid_, tag_, w_, j, d,
self.data[j+d:j+d+jump],
path)
def __bool__(self):
return bool(self.trunk)
@@ -758,7 +762,8 @@ def main(disk, roots=None, *,
d_ += max(bdepths.get(d, 0), 1)
leaf = (bid-(w-1), d, rid-(w-1),
next((tag for tag, _, _, _ in tags
next(
(tag for tag, _, _, _ in tags
if tag & 0xfff == TAG_BRANCH),
TAG_BRANCH))
@@ -937,7 +942,8 @@ def main(disk, roots=None, *,
treerepr(bid, w, bd, rid, tag)
if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
or args.get('btree')
else '',
2*w_width+1, '' if i != 0
else '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0
@@ -945,7 +951,8 @@ def main(disk, roots=None, *,
21+w_width, tagrepr(
tag, w if i == 0 else 0, len(data), None),
next(xxd(data, 8), '')
if not args.get('raw') and not args.get('no_truncate')
if not args.get('raw')
and not args.get('no_truncate')
else ''))
prbyd = rbyd
+5 -2
View File
@@ -109,14 +109,16 @@ def main(disk, blocks=None, *,
for block in blocks],
[off[0] if isinstance(off, tuple)
else off if off is not None
else size[0] if isinstance(size, tuple) and len(size) > 1
else size[0]
if isinstance(size, tuple) and len(size) > 1
else block[1] if isinstance(block, tuple)
else None
for block in blocks],
size[1] - size[0] if isinstance(size, tuple) and len(size) > 1
else size[0] if isinstance(size, tuple)
else size if size is not None
else off[1] - off[0] if isinstance(off, tuple) and len(off) > 1
else off[1] - off[0]
if isinstance(off, tuple) and len(off) > 1
else block_size)
# cat the blocks
@@ -126,6 +128,7 @@ def main(disk, blocks=None, *,
sys.stdout.buffer.write(data)
sys.stdout.flush()
if __name__ == "__main__":
import argparse
import sys
+1
View File
@@ -77,6 +77,7 @@ def main(errs, *,
except KeyError:
print('%s ?' % err)
if __name__ == "__main__":
import argparse
import sys
+56 -32
View File
@@ -320,7 +320,8 @@ class Rbyd:
if len(blocks) > 1:
# fetch all blocks
rbyds = [cls.fetch(f, block_size, block, trunk) for block in blocks]
rbyds = [cls.fetch(f, block_size, block, trunk)
for block in blocks]
# determine most recent revision
i = 0
for i_, rbyd in enumerate(rbyds):
@@ -333,7 +334,8 @@ class Rbyd:
i = i_
# keep track of the other blocks
rbyd = rbyds[i]
rbyd.redund_blocks = [rbyds[(i+1+j) % len(rbyds)].block
rbyd.redund_blocks = [
rbyds[(i+1+j) % len(rbyds)].block
for j in range(len(rbyds)-1)]
return rbyd
else:
@@ -488,7 +490,9 @@ class Rbyd:
done = not tag_ or (rid_, tag_) < (rid, tag)
return done, rid_, tag_, w_, j, d, self.data[j+d:j+d+jump], path
return (done, rid_, tag_, w_, j, d,
self.data[j+d:j+d+jump],
path)
def __bool__(self):
return bool(self.trunk)
@@ -750,7 +754,8 @@ class Rbyd:
d_ += max(bdepths.get(d, 0), 1)
leaf = (bid-(w-1), d, rid-(w-1),
next((tag for tag, _, _, _ in tags
next(
(tag for tag, _, _, _ in tags
if tag & 0xfff == TAG_BRANCH),
TAG_BRANCH))
@@ -878,7 +883,8 @@ class Rbyd:
if done:
return True, -1, 0, None
mdir = next(((tag, j, d, data)
mdir = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1181,7 +1187,8 @@ class GState:
# xor gstate
if tag not in self.gstate:
self.gstate[tag] = b''
self.gstate[tag] = bytes(a^b for a,b in it.zip_longest(
self.gstate[tag] = bytes(
a^b for a,b in it.zip_longest(
self.gstate[tag], data, fillvalue=0))
# parsers for some gstate
@@ -1208,7 +1215,8 @@ class GState:
count, _ = fromleb128(data)
return 'grm %s' % (
'none' if count == 0
else ' '.join('%d.%d' % (mbid//self.mleaf_weight, rid)
else ' '.join(
'%d.%d' % (mbid//self.mleaf_weight, rid)
for mbid, rid in self.grm)
if count <= 2
else '0x%x %d' % (count, len(data)))
@@ -1479,15 +1487,18 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
treerepr(bid, w, bd, rid, False, tag)
if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
'%*s ' % (2*w_width+1, '' if i != 0
or args.get('btree')
else '',
'%*s ' % (
2*w_width+1, '' if i != 0
else '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0
else ''),
21+2*w_width+1,
tagrepr(tag, w if i == 0 else 0, len(data), None),
21+2*w_width+1, tagrepr(
tag, w if i == 0 else 0, len(data), None),
next(xxd(data, 8), '')
if not args.get('raw') and not args.get('no_truncate')
if not args.get('raw')
and not args.get('no_truncate')
else ''))
prbyd = rbyd
@@ -1526,9 +1537,11 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
treerepr(bid, w, bd, rid, True, tag)
if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
or args.get('btree')
else '',
'\x1b[31m' if color and notes else '',
'%*s ' % (2*w_width+1, '%d-%d' % (bid-(w-1), bid) if w > 1
'%*s ' % (
2*w_width+1, '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0
else ''),
56+2*w_width+1, '%-*s %s' % (
@@ -1538,7 +1551,8 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
' w%d' % w if w else '',
block, off, size),
next(xxd(data, 8), '')
if not args.get('raw') and not args.get('no_truncate')
if not args.get('raw')
and not args.get('no_truncate')
else ''),
' (%s)' % ', '.join(notes) if notes else '',
'\x1b[m' if color and notes else ''))
@@ -1652,7 +1666,8 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
bptr = None
if (not args.get('struct_depth')
or len(path) < args.get('struct_depth')):
bptr = next(((tag, j, d, data)
bptr = next(
((tag, j, d, data)
for tag, j, d, data in tags
if (tag & 0xfff) == TAG_BLOCK),
None)
@@ -1754,12 +1769,12 @@ def main(disk, mroots=None, *,
for rid, tag, w, j, d, data in mroot:
if tag == TAG_DID:
did, d = fromleb128(data)
dir_dids.append(
(did, data[d:], -1, 0, mroot, rid, tag, w))
dir_dids.append((
did, data[d:], -1, 0, mroot, rid, tag, w))
elif tag == TAG_BOOKMARK:
did, d = fromleb128(data)
bookmark_dids.append(
(did, data[d:], -1, 0, mroot, rid, tag, w))
bookmark_dids.append((
did, data[d:], -1, 0, mroot, rid, tag, w))
# fetch the next mroot
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, TAG_MROOT)
@@ -1817,7 +1832,8 @@ def main(disk, mroots=None, *,
corrupted = True
continue
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1916,7 +1932,8 @@ def main(disk, mroots=None, *,
for i, (repr_, tag, j, data) in enumerate(config.repr()):
print('%12s %*s %-*s %s' % (
'{%s}:' % ','.join('%04x' % block
for block in it.chain([mroot.block],
for block in it.chain(
[mroot.block],
mroot.redund_blocks))
if i == 0 else '',
2*w_width+1, '%d.%d' % (-1, -1)
@@ -1924,7 +1941,8 @@ def main(disk, mroots=None, *,
21+w_width, repr_,
next(xxd(data, 8), '')
if not args.get('raw')
and not args.get('no_truncate') else ''))
and not args.get('no_truncate')
else ''))
# show on-disk encoding
if args.get('raw') or args.get('no_truncate'):
@@ -1943,7 +1961,8 @@ def main(disk, mroots=None, *,
21+w_width, repr_,
next(xxd(data, 8), '')
if not args.get('raw')
and not args.get('no_truncate') else ''))
and not args.get('no_truncate')
else ''))
# show on-disk encoding
if args.get('raw') or args.get('no_truncate'):
@@ -1959,13 +1978,16 @@ def main(disk, mroots=None, *,
print('%s%12s %*s %-*s %s%s' % (
'\x1b[90m' if color else '',
'{%s}:' % ','.join('%04x' % block
for block in it.chain([mdir.block],
for block in it.chain(
[mdir.block],
mdir.redund_blocks)),
2*w_width+1, '%d.%d' % (mbid//mleaf_weight, -1),
2*w_width+1, '%d.%d' % (
mbid//mleaf_weight, -1),
21+w_width, tagrepr(tag, 0, len(data)),
next(xxd(data, 8), '')
if not args.get('raw')
and not args.get('no_truncate') else '',
and not args.get('no_truncate')
else '',
'\x1b[m' if color else ''))
# show on-disk encoding
@@ -2053,13 +2075,16 @@ def main(disk, mroots=None, *,
or tag == TAG_ORPHAN)
else '',
'{%s}:' % ','.join('%04x' % block
for block in it.chain([mdir.block],
for block in it.chain(
[mdir.block],
mdir.redund_blocks))
if mbid != pmbid else '',
2*w_width+1, '%d.%d-%d' % (
mbid//mleaf_weight, rid-(w-1), rid)
if w > 1 else '%d.%d' % (mbid//mleaf_weight, rid)
if w > 0 else '',
if w > 1
else '%d.%d' % (mbid//mleaf_weight, rid)
if w > 0
else '',
f_width, '%s%s' % (
prefixes[0+(i==len(dir)-1)],
name.decode('utf8')),
@@ -2154,8 +2179,7 @@ def main(disk, mroots=None, *,
rid, TAG_DID)
if not done and rid_ == rid and tag_ == TAG_DID:
did_, _ = fromleb128(data)
rec_dir(
did_,
rec_dir(did_,
depth-1,
(prefixes[2+(i==len(dir)-1)] + "|-> ",
prefixes[2+(i==len(dir)-1)] + "'-> ",
+39 -19
View File
@@ -304,7 +304,8 @@ class Rbyd:
if len(blocks) > 1:
# fetch all blocks
rbyds = [cls.fetch(f, block_size, block, trunk) for block in blocks]
rbyds = [cls.fetch(f, block_size, block, trunk)
for block in blocks]
# determine most recent revision
i = 0
for i_, rbyd in enumerate(rbyds):
@@ -317,7 +318,8 @@ class Rbyd:
i = i_
# keep track of the other blocks
rbyd = rbyds[i]
rbyd.redund_blocks = [rbyds[(i+1+j) % len(rbyds)].block
rbyd.redund_blocks = [
rbyds[(i+1+j) % len(rbyds)].block
for j in range(len(rbyds)-1)]
return rbyd
else:
@@ -472,7 +474,9 @@ class Rbyd:
done = not tag_ or (rid_, tag_) < (rid, tag)
return done, rid_, tag_, w_, j, d, self.data[j+d:j+d+jump], path
return (done, rid_, tag_, w_, j, d,
self.data[j+d:j+d+jump],
path)
def __bool__(self):
return bool(self.trunk)
@@ -734,7 +738,8 @@ class Rbyd:
d_ += max(bdepths.get(d, 0), 1)
leaf = (bid-(w-1), d, rid-(w-1),
next((tag for tag, _, _, _ in tags
next(
(tag for tag, _, _, _ in tags
if tag & 0xfff == TAG_BRANCH),
TAG_BRANCH))
@@ -947,7 +952,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1098,7 +1104,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1128,7 +1135,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1318,7 +1326,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1397,7 +1406,8 @@ def main(disk, mroots=None, *,
was = None
for d in range(t_depth):
t, c, was = branchrepr(
(mbid-max(mw-1, 0), md, mrid-max(mw-1, 0), rid, tag),
(mbid-max(mw-1, 0), md,
mrid-max(mw-1, 0), rid, tag),
d, was)
trunk.append('%s%s%s%s' % (
@@ -1417,18 +1427,22 @@ def main(disk, mroots=None, *,
# show human-readable tag representation
print('%12s %s%s' % (
'{%s}:' % ','.join('%04x' % block
for block in it.chain([mdir.block],
for block in it.chain(
[mdir.block],
mdir.redund_blocks))
if i == 0 else '',
treerepr(mbid-max(mw-1, 0), 0, md, 0, rid, tag)
if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
or args.get('btree')
else '',
'%*s %-*s%s' % (
2*w_width+1, '%d.%d-%d' % (
mbid//mleaf_weight, rid-(w-1), rid)
if w > 1 else '%d.%d' % (mbid//mleaf_weight, rid)
if w > 0 or i == 0 else '',
if w > 1
else '%d.%d' % (mbid//mleaf_weight, rid)
if w > 0 or i == 0
else '',
21+w_width, tagrepr(tag, w, len(data), j),
' %s' % next(xxd(data, 8), '')
if not args.get('raw')
@@ -1467,7 +1481,8 @@ def main(disk, mroots=None, *,
treerepr(bid, w, bd, rid, 0, tag)
if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
or args.get('btree')
else '',
2*w_width+1, '' if i != 0
else '%d-%d' % (
(bid-(w-1))//mleaf_weight,
@@ -1478,7 +1493,8 @@ def main(disk, mroots=None, *,
21+w_width, tagrepr(
tag, w if i == 0 else 0, len(data), None),
next(xxd(data, 8), '')
if not args.get('raw') and not args.get('no_truncate')
if not args.get('raw')
and not args.get('no_truncate')
else ''))
prbyd = rbyd
@@ -1526,7 +1542,8 @@ def main(disk, mroots=None, *,
if not mroot:
print('{%s}: %s%s%s' % (
','.join('%04x' % block
for block in it.chain([mroot.block],
for block in it.chain(
[mroot.block],
mroot.redund_blocks)),
'\x1b[31m' if color else '',
'(corrupted mroot %s)' % mroot.addr(),
@@ -1561,7 +1578,8 @@ def main(disk, mroots=None, *,
if not mdir:
print('{%s}: %s%s%s' % (
','.join('%04x' % block
for block in it.chain([mdir.block],
for block in it.chain(
[mdir.block],
mdir.redund_blocks)),
'\x1b[31m' if color else '',
'(corrupted mdir %s)' % mdir.addr(),
@@ -1637,7 +1655,8 @@ def main(disk, mroots=None, *,
mdir__ = None
if (not args.get('depth')
or mdepth+len(path) < args.get('depth')):
mdir__ = next(((tag, j, d, data)
mdir__ = next(
((tag, j, d, data)
for tag, j, d, data in tags
if tag == TAG_MDIR),
None)
@@ -1658,7 +1677,8 @@ def main(disk, mroots=None, *,
if not mdir_:
print('{%s}: %*s%s%s%s' % (
','.join('%04x' % block
for block in it.chain([mdir_.block],
for block in it.chain(
[mdir_.block],
mdir_.redund_blocks)),
t_width, '',
'\x1b[31m' if color else '',
+19 -10
View File
@@ -7,6 +7,7 @@ import math as mt
import os
import struct
COLORS = [
'34', # blue
'31', # red
@@ -585,7 +586,9 @@ def dbg_log(data, block_size, rev, eoff, weight, *,
'\x1b[90m' if color and j >= eoff else '',
j,
'\x1b[m' if color and j >= eoff else '',
lifetime_width, lifetimerepr(j) if args.get('lifetimes') else '',
lifetime_width, lifetimerepr(j)
if args.get('lifetimes')
else '',
'\x1b[90m' if color and j >= eoff else '',
2*w_width+1, '' if (tag & 0xe000) != 0x0000
else '%d-%d' % (rid-(w-1), rid) if w > 1
@@ -593,12 +596,15 @@ def dbg_log(data, block_size, rev, eoff, weight, *,
56+w_width, '%-*s %s' % (
21+w_width, tagrepr(tag, w, size, j),
next(xxd(data[j+d:j+d+min(size, 8)], 8), '')
if not args.get('raw') and not args.get('no_truncate')
and not tag & TAG_ALT else ''),
if not args.get('raw')
and not args.get('no_truncate')
and not tag & TAG_ALT
else ''),
' (%s)' % ', '.join(notes) if notes else '',
'\x1b[m' if color and j >= eoff else '',
' %s' % jumprepr(j)
if args.get('jumps') and not notes else ''))
if args.get('jumps') and not notes
else ''))
# show on-disk encoding of tags
if args.get('raw'):
@@ -852,14 +858,17 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
print('%08x: %s%*s %-*s %s' % (
j,
treerepr(rid, tag)
if args.get('tree') or args.get('rbyd') else '',
2*w_width+1, '%d-%d' % (rid-(w-1), rid)
if w > 1 else rid
if w > 0 or i == 0 else '',
if args.get('tree') or args.get('rbyd')
else '',
2*w_width+1, '%d-%d' % (rid-(w-1), rid) if w > 1
else rid if w > 0 or i == 0
else '',
21+w_width, tagrepr(tag, w, size, j),
next(xxd(data[j+d:j+d+min(size, 8)], 8), '')
if not args.get('raw') and not args.get('no_truncate')
and not tag & TAG_ALT else ''))
if not args.get('raw')
and not args.get('no_truncate')
and not tag & TAG_ALT
else ''))
# show on-disk encoding of tags
if args.get('raw'):
+1
View File
@@ -319,6 +319,7 @@ def main(tags, *,
data = f.read(2+5+5)
dbg_tag(data)
if __name__ == "__main__":
import argparse
import sys
+1
View File
@@ -63,6 +63,7 @@ def main(paths, **args):
else:
print('%01x' % parity(xor))
if __name__ == "__main__":
import argparse
import sys
+47 -35
View File
@@ -27,8 +27,8 @@ import subprocess as sp
import tempfile
import zipfile
# TODO support non-zip perf results?
# TODO support non-zip perf results?
PERF_PATH = ['perf']
PERF_EVENTS = 'cycles,branch-misses,branches,cache-misses,cache-references'
@@ -249,15 +249,15 @@ def collect_syms_and_lines(obj_path, *,
'\s+.*'
'\s+(?P<path>[^\s]+)'
# matches line opcodes
'|' '\[[^\]]*\]\s+'
'(?:'
'|' '\[[^\]]*\]\s+' '(?:'
'(?P<op_special>Special)'
'|' '(?P<op_copy>Copy)'
'|' '(?P<op_end>End of Sequence)'
'|' 'File .*?to (?:entry )?(?P<op_file>\d+)'
'|' 'Line .*?to (?P<op_line>[0-9]+)'
'|' '(?:Address|PC) .*?to (?P<op_addr>[0x0-9a-fA-F]+)'
'|' '.' ')*'
'|' '.'
')*'
')$', re.IGNORECASE)
# figure out symbol addresses and file+line ranges
@@ -616,7 +616,8 @@ def collect(perf_paths, *,
with mp.Pool(jobs) as p:
for results_ in p.imap_unordered(
starapply,
((collect_job, (path, i), args) for path, i in records)):
((collect_job, (path, i), args)
for path, i in records)):
results.extend(results_)
else:
results = []
@@ -690,12 +691,13 @@ def table(Result, results, diff_results=None, *,
r = max(results_,
key=lambda r: tuple(
tuple(
(getattr(r, k),)
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])
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])))
@@ -729,7 +731,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -740,9 +743,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -750,8 +756,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -835,10 +840,13 @@ def table(Result, results, diff_results=None, *,
names_.sort(
key=lambda n: tuple(
(getattr(table_[n], k),)
if getattr(table_.get(n), k, None) is not None
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])),
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_):
@@ -860,8 +868,7 @@ def table(Result, results, diff_results=None, *,
# recurse?
if depth_ > 1:
recurse(
r.children,
recurse(r.children,
depth_-1,
seen | {name},
(prefixes[2+is_last] + "|-> ",
@@ -881,8 +888,7 @@ def table(Result, results, diff_results=None, *,
# recursive entries
if name in table and depth > 1:
recurse(
table[name].children,
recurse(table[name].children,
depth-1,
{name},
("|-> ",
@@ -1006,9 +1012,11 @@ def annotate(Result, results, *,
line,
'%s cycles' % r.cycles
if not branches and not caches
else '%s bmisses, %s branches' % (r.bmisses, r.branches)
else '%s bmisses, %s branches' % (
r.bmisses, r.branches)
if branches
else '%s cmisses, %s caches' % (r.cmisses, r.caches))
else '%s cmisses, %s caches' % (
r.cmisses, r.caches))
if args['color']:
if float(getattr(r, tk)) / max_ >= t1:
@@ -1084,14 +1092,16 @@ def report(perf_paths, *,
writer = csv.DictWriter(f,
(by if by is not None else PerfResult._by)
+ [k for k in (
fields if fields is not None else PerfResult._fields)])
fields if fields is not None
else PerfResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else PerfResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else PerfResult._fields)})
fields if fields is not None
else PerfResult._fields)})
# find previous results?
if args.get('diff'):
@@ -1240,8 +1250,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -1257,15 +1267,15 @@ if __name__ == "__main__":
parser.add_argument(
'-g', '--propagate',
type=lambda x: int(x, 0),
help="Depth to propagate samples up the call-stack. 0 propagates up "
"to the entry point, 1 does no propagation. Defaults to 0.")
help="Depth to propagate samples up the call-stack. 0 propagates "
"up to the entry point, 1 does no propagation. Defaults to 0.")
parser.add_argument(
'-z', '--depth',
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Depth of function calls to show. 0 shows all calls unless we "
"find a cycle. Defaults to 0.")
help="Depth of function calls to show. 0 shows all calls unless "
"we find a cycle. Defaults to 0.")
parser.add_argument(
'-t', '--hot',
nargs='?',
@@ -1280,8 +1290,9 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: tuple(float(x) for x in x.split(',')),
const=THRESHOLD,
help="Show lines with samples above this threshold as a percent of "
"all lines. Defaults to %s." % ','.join(str(t) for t in THRESHOLD))
help="Show lines with samples above this threshold as a percent "
"of all lines. Defaults to "
"%s." % ','.join(str(t) for t in THRESHOLD))
parser.add_argument(
'-C', '--context',
type=lambda x: int(x, 0),
@@ -1291,7 +1302,8 @@ if __name__ == "__main__":
'-W', '--width',
type=lambda x: int(x, 0),
default=80,
help="Assume source is styled with this many columns. Defaults to 80.")
help="Assume source is styled with this many columns. Defaults "
"to 80.")
parser.add_argument(
'--color',
choices=['never', 'always', 'auto'],
+59 -46
View File
@@ -155,15 +155,15 @@ def collect_syms_and_lines(obj_path, *,
'\s+.*'
'\s+(?P<path>[^\s]+)'
# matches line opcodes
'|' '\[[^\]]*\]\s+'
'(?:'
'|' '\[[^\]]*\]\s+' '(?:'
'(?P<op_special>Special)'
'|' '(?P<op_copy>Copy)'
'|' '(?P<op_end>End of Sequence)'
'|' 'File .*?to (?:entry )?(?P<op_file>\d+)'
'|' 'Line .*?to (?P<op_line>[0-9]+)'
'|' '(?:Address|PC) .*?to (?P<op_addr>[0x0-9a-fA-F]+)'
'|' '.' ')*'
'|' '.'
')*'
')$', re.IGNORECASE)
# figure out symbol addresses
@@ -296,7 +296,8 @@ def collect_job(path, start, stop, syms, sym_at, lines, line_at, *,
depth=1,
**args):
trace_pattern = re.compile(
'^(?P<file>[^:]*):(?P<line>[0-9]+):trace:\s*(?P<prefix>[^\s]*?bd_)(?:'
'^(?P<file>[^:]*):(?P<line>[0-9]+):trace:\s*'
'(?P<prefix>[^\s]*?bd_)(?:'
'(?P<read>read)\('
'\s*(?P<read_ctx>\w+)' '\s*,'
'\s*(?P<read_block>\w+)' '\s*,'
@@ -312,7 +313,8 @@ def collect_job(path, start, stop, syms, sym_at, lines, line_at, *,
'|' '(?P<erase>erase)\('
'\s*(?P<erase_ctx>\w+)' '\s*,'
'\s*(?P<erase_block>\w+)'
'\s*\(\s*(?P<erase_size>\w+)\s*\)' '\s*\)' ')\s*$')
'\s*\(\s*(?P<erase_size>\w+)\s*\)' '\s*\)'
')\s*$')
frame_pattern = re.compile(
'^\s+at (?P<addr>\w+)\s*$')
@@ -338,9 +340,7 @@ def collect_job(path, start, stop, syms, sym_at, lines, line_at, *,
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(file)
== os.path.abspath(s)
if not any(os.path.abspath(file) == os.path.abspath(s)
for s in sources):
return
else:
@@ -492,8 +492,7 @@ def collect_job(path, start, stop, syms, sym_at, lines, line_at, *,
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(file)
== os.path.abspath(s)
os.path.abspath(file) == os.path.abspath(s)
for s in sources):
at_cache[addr] = None
continue
@@ -573,7 +572,8 @@ def collect(obj_path, trace_paths, *,
with mp.Pool(jobs) as p:
for results_ in p.imap_unordered(
starapply,
((collect_job, (path, start, stop,
((collect_job,
(path, start, stop,
syms, sym_at, lines, line_at),
args)
for path, ranges in zip(trace_paths, trace_ranges)
@@ -583,7 +583,8 @@ def collect(obj_path, trace_paths, *,
else:
results = []
for path in trace_paths:
results.extend(collect_job(path, None, None,
results.extend(collect_job(
path, None, None,
syms, sym_at, lines, line_at,
**args))
@@ -654,12 +655,13 @@ def table(Result, results, diff_results=None, *,
r = max(results_,
key=lambda r: tuple(
tuple(
(getattr(r, k),)
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])
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])))
@@ -693,7 +695,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -704,9 +707,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -714,8 +720,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -799,10 +804,13 @@ def table(Result, results, diff_results=None, *,
names_.sort(
key=lambda n: tuple(
(getattr(table_[n], k),)
if getattr(table_.get(n), k, None) is not None
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])),
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_):
@@ -824,8 +832,7 @@ def table(Result, results, diff_results=None, *,
# recurse?
if depth_ > 1:
recurse(
r.children,
recurse(r.children,
depth_-1,
seen | {name},
(prefixes[2+is_last] + "|-> ",
@@ -845,8 +852,7 @@ def table(Result, results, diff_results=None, *,
# recursive entries
if name in table and depth > 1:
recurse(
table[name].children,
recurse(table[name].children,
depth-1,
{name},
("|-> ",
@@ -1062,14 +1068,16 @@ def report(obj_path='', trace_paths=[], *,
writer = csv.DictWriter(f,
(by if by is not None else PerfBdResult._by)
+ [k for k in (
fields if fields is not None else PerfBdResult._fields)])
fields if fields is not None
else PerfBdResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else PerfBdResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else PerfBdResult._fields)})
fields if fields is not None
else PerfBdResult._fields)})
# find previous results?
if args.get('diff'):
@@ -1209,8 +1217,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -1218,15 +1226,15 @@ if __name__ == "__main__":
parser.add_argument(
'-g', '--propagate',
type=lambda x: int(x, 0),
help="Depth to propagate samples up the call-stack. 0 propagates up "
"to the entry point, 1 does no propagation. Defaults to 0.")
help="Depth to propagate samples up the call-stack. 0 propagates "
"up to the entry point, 1 does no propagation. Defaults to 0.")
parser.add_argument(
'-z', '--depth',
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Depth of function calls to show. 0 shows all calls unless we "
"find a cycle. Defaults to 0.")
help="Depth of function calls to show. 0 shows all calls unless "
"we find a cycle. Defaults to 0.")
parser.add_argument(
'-t', '--hot',
nargs='?',
@@ -1241,29 +1249,33 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: tuple(float(x) for x in x.split(',')),
const=THRESHOLD,
help="Show lines with any ops above this threshold as a percent of "
"all lines. Defaults to %s." % ','.join(str(t) for t in THRESHOLD))
help="Show lines with any ops above this threshold as a percent "
"of all lines. Defaults to "
"%s." % ','.join(str(t) for t in THRESHOLD))
parser.add_argument(
'--read-threshold',
nargs='?',
type=lambda x: tuple(float(x) for x in x.split(',')),
const=THRESHOLD,
help="Show lines with reads above this threshold as a percent of "
"all lines. Defaults to %s." % ','.join(str(t) for t in THRESHOLD))
help="Show lines with reads above this threshold as a percent "
"of all lines. Defaults to "
"%s." % ','.join(str(t) for t in THRESHOLD))
parser.add_argument(
'--prog-threshold',
nargs='?',
type=lambda x: tuple(float(x) for x in x.split(',')),
const=THRESHOLD,
help="Show lines with progs above this threshold as a percent of "
"all lines. Defaults to %s." % ','.join(str(t) for t in THRESHOLD))
help="Show lines with progs above this threshold as a percent "
"of all lines. Defaults to "
"%s." % ','.join(str(t) for t in THRESHOLD))
parser.add_argument(
'--erase-threshold',
nargs='?',
type=lambda x: tuple(float(x) for x in x.split(',')),
const=THRESHOLD,
help="Show lines with erases above this threshold as a percent of "
"all lines. Defaults to %s." % ','.join(str(t) for t in THRESHOLD))
help="Show lines with erases above this threshold as a percent "
"of all lines. Defaults to "
"%s." % ','.join(str(t) for t in THRESHOLD))
parser.add_argument(
'-C', '--context',
type=lambda x: int(x, 0),
@@ -1273,7 +1285,8 @@ if __name__ == "__main__":
'-W', '--width',
type=lambda x: int(x, 0),
default=80,
help="Assume source is styled with this many columns. Defaults to 80.")
help="Assume source is styled with this many columns. Defaults "
"to 80.")
parser.add_argument(
'--color',
choices=['never', 'always', 'auto'],
+46 -34
View File
@@ -684,7 +684,8 @@ class Grid:
self.xweights = new_xweights
self.yweights = self_yweights + other.yweights
self.map = self_map | {(x, y+len(self_yweights)): s
self.map = self_map | {
(x, y+len(self_yweights)): s
for (x, y), s in other_map.items()}
else:
for s in self.subplots:
@@ -693,7 +694,8 @@ class Grid:
self.xweights = new_xweights
self.yweights = other.yweights + self_yweights
self.map = other_map | {(x, y+len(other.yweights)): s
self.map = other_map | {
(x, y+len(other.yweights)): s
for (x, y), s in self_map.items()}
if dir in ['right', 'left']:
@@ -782,7 +784,8 @@ class Grid:
self.xweights = self_xweights + other.xweights
self.yweights = new_yweights
self.map = self_map | {(x+len(self_xweights), y): s
self.map = self_map | {
(x+len(self_xweights), y): s
for (x, y), s in other_map.items()}
else:
for s in self.subplots:
@@ -791,7 +794,8 @@ class Grid:
self.xweights = other.xweights + self_xweights
self.yweights = new_yweights
self.map = other_map | {(x+len(other.xweights), y): s
self.map = other_map | {
(x+len(other.xweights), y): s
for (x, y), s in self_map.items()}
@@ -1012,8 +1016,7 @@ def main(csv_paths, *,
# if y not specified, guess it's anything not in by/defines/x/renames
all_y_ = all_y
if not all_y:
all_y_ = [
k for k in fields_
all_y_ = [k for k in fields_
if k not in all_by
and not any(k == k_ for k_, _ in all_defines)
and not any(k == old_k for _, old_k in all_renames)]
@@ -1048,7 +1051,8 @@ def main(csv_paths, *,
else '%s ' % dataline_chars_[name]
if line_chars is not None
else '',
all_labels_[name] if all_labels
all_labels_[name]
if all_labels
else ','.join(name))
if label:
@@ -1092,7 +1096,9 @@ def main(csv_paths, *,
for i in range(legend_cols)]
if (legend_cols <= 1
or sum(legend_widths)+2*(legend_cols-1)
+ max(sum(s.xmargin[:2]) for s in grid if s.x == 0)
+ max(sum(s.xmargin[:2])
for s in grid
if s.x == 0)
<= width_):
break
legend_cols -= 1
@@ -1105,7 +1111,9 @@ def main(csv_paths, *,
for i in range(legend_cols)]
if (legend_cols <= 1
or sum(legend_widths)+2*(legend_cols-1)
+ max(sum(s.xmargin[:2]) for s in grid if s.x == 0)
+ max(sum(s.xmargin[:2])
for s in grid
if s.x == 0)
<= width_):
break
legend_cols -= 1
@@ -1125,7 +1133,8 @@ def main(csv_paths, *,
# but that's the best we can do
for s in grid:
# fit xunits
minwidth = sum(s.xmargin) + max(2,
minwidth = sum(s.xmargin) + max(
2,
2*((5 if s.x2 else 4)+len(s.xunits))
if s.xticklabels is None
else sum(len(t) for t in s.xticklabels))
@@ -1172,7 +1181,8 @@ def main(csv_paths, *,
for name, dataset in subdatasets.items()
if len(all_x) <= 1
or name[-(1 if len(all_y_) <= 1 else 2)] in x_
if len(all_y_) <= 1 or name[-1] in y_])
if len(all_y_) <= 1
or name[-1] in y_])
# find actual xlim/ylim
xlim_ = (
@@ -1250,7 +1260,8 @@ def main(csv_paths, *,
if legend_above and legend_:
for i in range(0, len(legend_), legend_cols):
f.writeln('%*s%s' % (
max(sum(xmargin[:2])
max(
sum(xmargin[:2])
+ (width_-xmargin[1]
- (sum(legend_widths)+2*(legend_cols-1)))
// 2,
@@ -1263,8 +1274,7 @@ def main(csv_paths, *,
for row in range(height_):
# draw ylabel?
f.write(
'%s ' % ''.join(
f.write('%s ' % ''.join(
('%*s%s%*s' % (
ymargin[-1], '',
line.center(height_-sum(ymargin)),
@@ -1344,7 +1354,8 @@ def main(csv_paths, *,
else s.xticklabels[0],
s.width - (2*((5 if s.x2 else 4)+len(s.xunits))
if s.xticklabels is None
else sum(len(t) for t in s.xticklabels)), '',
else sum(len(t)
for t in s.xticklabels)), '',
(5 if s.x2 else 4) + len(s.xunits)
if s.xticklabels is None
else len(s.xticklabels[1]),
@@ -1384,17 +1395,16 @@ def main(csv_paths, *,
if legend_below and legend_:
for i in range(0, len(legend_), legend_cols):
f.writeln('%*s%s' % (
max(sum(xmargin[:2])
max(
sum(xmargin[:2])
+ (width_-xmargin[1]
- (sum(legend_widths)+2*(legend_cols-1)))
// 2,
0), '',
' '.join('%s%s%s' % (
'\x1b[%sm' % legend_[i+j][1]
if color else '',
'\x1b[%sm' % legend_[i+j][1] if color else '',
'%-*s' % (legend_widths[j], legend_[i+j][0]),
'\x1b[m'
if color else '')
'\x1b[m' if color else '')
for j in range(min(legend_cols, len(legend_)-i)))))
@@ -1452,7 +1462,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Group by this field. Can rename fields with new_name=old_name.")
help="Group by this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-x',
action='append',
@@ -1483,8 +1494,8 @@ if __name__ == "__main__":
{v.strip() for v in vs.split(',')})
)(*x.split('=', 1)),
action='append',
help="Only include results where this field is this value. May include "
"comma-separated options.")
help="Only include results where this field is this value. May "
"include comma-separated options.")
parser.add_argument(
'-L', '--label',
action='append',
@@ -1493,9 +1504,9 @@ if __name__ == "__main__":
re.sub(r'\\([=\\])', r'\1', k.strip()),
tuple(v.strip() for v in vs.split(',')))
)(*re.split(r'(?<!\\)=', x, 1)),
help="Use this label for a given group, where a group is roughly the "
"comma-separated values in the -b/--by, -x, and -y fields. Also "
"provides an ordering. Accepts escaped equals.")
help="Use this label for a given group, where a group is roughly "
"the comma-separated values in the -b/--by, -x, and -y "
"fields. Also provides an ordering. Accepts escaped equals.")
parser.add_argument(
'--color',
choices=['never', 'always', 'auto'],
@@ -1504,8 +1515,8 @@ if __name__ == "__main__":
parser.add_argument(
'-⣿', '--braille',
action='store_true',
help="Use 2x4 unicode braille characters. Note that braille characters "
"sometimes suffer from inconsistent widths.")
help="Use 2x4 unicode braille characters. Note that braille "
"characters sometimes suffer from inconsistent widths.")
parser.add_argument(
'-.', '--points',
action='store_true',
@@ -1626,10 +1637,11 @@ if __name__ == "__main__":
parser.add_argument(
'--subplot-above',
action=AppendSubplot,
help="Add subplot above with the same dataset. Takes an arg string to "
"control the subplot which supports most (but not all) of the "
"parameters listed here. The relative dimensions of the subplot "
"can be controlled with -W/-H which now take a percentage.")
help="Add subplot above with the same dataset. Takes an arg "
"string to control the subplot which supports most (but "
"not all) of the parameters listed here. The relative "
"dimensions of the subplot can be controlled with -W/-H "
"which now take a percentage.")
parser.add_argument(
'--subplot-below',
action=AppendSubplot,
@@ -1661,8 +1673,8 @@ if __name__ == "__main__":
parser.add_argument(
'-s', '--sleep',
type=float,
help="Time in seconds to sleep between redraws when running with -k. "
"Defaults to 0.01.")
help="Time in seconds to sleep between redraws when running "
"with -k. Defaults to 0.01.")
def dictify(ns):
if hasattr(ns, 'subplots'):
+26 -19
View File
@@ -25,6 +25,7 @@ import time
import matplotlib as mpl
import matplotlib.pyplot as plt
# some nicer colors borrowed from Seaborn
# note these include a non-opaque alpha
COLORS = [
@@ -148,8 +149,8 @@ class AutoMultipleLocator(mpl.ticker.MultipleLocator):
nbins = np.clip(self.axis.get_tick_space(), 1, 9)
# find the best power, use this as our locator's actual base
scale = self.base
** (mt.ceil(mt.log((vmax-vmin) / (nbins+1), self.base)))
scale = (self.base
** (mt.ceil(mt.log((vmax-vmin) / (nbins+1), self.base))))
self.set_params(scale)
return super().__call__()
@@ -423,7 +424,8 @@ class Grid:
self.xweights = new_xweights
self.yweights = self_yweights + other.yweights
self.map = self_map | {(x, y+len(self_yweights)): s
self.map = self_map | {
(x, y+len(self_yweights)): s
for (x, y), s in other_map.items()}
else:
for s in self.subplots:
@@ -432,7 +434,8 @@ class Grid:
self.xweights = new_xweights
self.yweights = other.yweights + self_yweights
self.map = other_map | {(x, y+len(other.yweights)): s
self.map = other_map | {
(x, y+len(other.yweights)): s
for (x, y), s in self_map.items()}
if dir in ['right', 'left']:
@@ -521,7 +524,8 @@ class Grid:
self.xweights = self_xweights + other.xweights
self.yweights = new_yweights
self.map = self_map | {(x+len(self_xweights), y): s
self.map = self_map | {
(x+len(self_xweights), y): s
for (x, y), s in other_map.items()}
else:
for s in self.subplots:
@@ -530,7 +534,8 @@ class Grid:
self.xweights = other.xweights + self_xweights
self.yweights = new_yweights
self.map = other_map | {(x+len(other.xweights), y): s
self.map = other_map | {
(x+len(other.xweights), y): s
for (x, y), s in self_map.items()}
@@ -743,8 +748,7 @@ def main(csv_paths, output, *,
# if y not specified, guess it's anything not in by/defines/x/renames
if not all_y:
all_y = [
k for k in fields_
all_y = [k for k in fields_
if k not in all_by
and not any(k == k_ for k_, _ in all_defines)
and not any(k == old_k for _, old_k in all_renames)]
@@ -767,7 +771,8 @@ def main(csv_paths, output, *,
grid = Grid.fromargs(**subplot, subplots=subplots)
# create a matplotlib plot
fig = plt.figure(figsize=(
fig = plt.figure(
figsize=(
width/plt.rcParams['figure.dpi'],
height/plt.rcParams['figure.dpi']),
layout='constrained',
@@ -1103,7 +1108,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Group by this field. Can rename fields with new_name=old_name.")
help="Group by this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-x',
action='append',
@@ -1134,8 +1140,8 @@ if __name__ == "__main__":
{v.strip() for v in vs.split(',')})
)(*x.split('=', 1)),
action='append',
help="Only include results where this field is this value. May include "
"comma-separated options.")
help="Only include results where this field is this value. May "
"include comma-separated options.")
parser.add_argument(
'-L', '--label',
action='append',
@@ -1144,9 +1150,9 @@ if __name__ == "__main__":
re.sub(r'\\([=\\])', r'\1', k.strip()),
tuple(v.strip() for v in vs.split(',')))
)(*re.split(r'(?<!\\)=', x, 1)),
help="Use this label for a given group, where a group is roughly the "
"comma-separated values in the -b/--by, -x, and -y fields. Also "
"provides an ordering. Accepts escaped equals.")
help="Use this label for a given group, where a group is roughly "
"the comma-separated values in the -b/--by, -x, and -y "
"fields. Also provides an ordering. Accepts escaped equals.")
parser.add_argument(
'-.', '--points',
action='store_true',
@@ -1302,10 +1308,11 @@ if __name__ == "__main__":
parser.add_argument(
'--subplot-above',
action=AppendSubplot,
help="Add subplot above with the same dataset. Takes an arg string to "
"control the subplot which supports most (but not all) of the "
"parameters listed here. The relative dimensions of the subplot "
"can be controlled with -W/-H which now take a percentage.")
help="Add subplot above with the same dataset. Takes an arg "
"string to control the subplot which supports most (but "
"not all) of the parameters listed here. The relative "
"dimensions of the subplot can be controlled with -W/-H "
"which now take a percentage.")
parser.add_argument(
'--subplot-below',
action=AppendSubplot,
+19 -22
View File
@@ -13,6 +13,7 @@
import re
import sys
LIMIT = 16
CMP = {
@@ -133,15 +134,14 @@ def write_header(f, limit=LIMIT):
# write assert macros
for op, cmp in sorted(CMP.items()):
f.writeln("#define __PRETTY_ASSERT_BOOL_%s(lh, rh) do { \\"
% cmp.upper())
f.writeln("#define __PRETTY_ASSERT_BOOL_%s(lh, rh) do { \\" % (
cmp.upper()))
f.writeln(" bool _lh = !!(lh); \\")
f.writeln(" bool _rh = !!(rh); \\")
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
f.writeln(" __pretty_assert_print( \\")
f.writeln(" __FILE__, __LINE__, \\")
f.writeln(" __pretty_assert_bool, \"%s\", \\"
% cmp)
f.writeln(" __pretty_assert_bool, \"%s\", \\" % cmp)
f.writeln(" &_lh, 0, \\")
f.writeln(" &_rh, 0); \\")
f.writeln(" __builtin_trap(); \\")
@@ -149,15 +149,14 @@ def write_header(f, limit=LIMIT):
f.writeln("} while (0)")
f.writeln()
for op, cmp in sorted(CMP.items()):
f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\"
% cmp.upper())
f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\" % (
cmp.upper()))
f.writeln(" __typeof__(rh) _lh = lh; \\")
f.writeln(" __typeof__(rh) _rh = rh; \\")
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
f.writeln(" __pretty_assert_print( \\")
f.writeln(" __FILE__, __LINE__, \\")
f.writeln(" __pretty_assert_int, \"%s\", \\"
% cmp)
f.writeln(" __pretty_assert_int, \"%s\", \\" % cmp)
f.writeln(" &(intmax_t){(intmax_t)_lh}, 0, \\")
f.writeln(" &(intmax_t){(intmax_t)_rh}, 0); \\")
f.writeln(" __builtin_trap(); \\")
@@ -165,15 +164,14 @@ def write_header(f, limit=LIMIT):
f.writeln("} while (0)")
f.writeln()
for op, cmp in sorted(CMP.items()):
f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\"
% cmp.upper())
f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\" % (
cmp.upper()))
f.writeln(" const void *_lh = lh; \\")
f.writeln(" const void *_rh = rh; \\")
f.writeln(" if (!(memcmp(_lh, _rh, size) %s 0)) { \\" % op)
f.writeln(" __pretty_assert_print( \\")
f.writeln(" __FILE__, __LINE__, \\")
f.writeln(" __pretty_assert_mem, \"%s\", \\"
% cmp)
f.writeln(" __pretty_assert_mem, \"%s\", \\" % cmp)
f.writeln(" _lh, size, \\")
f.writeln(" _rh, size); \\")
f.writeln(" __builtin_trap(); \\")
@@ -181,15 +179,14 @@ def write_header(f, limit=LIMIT):
f.writeln("} while (0)")
f.writeln()
for op, cmp in sorted(CMP.items()):
f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\"
% cmp.upper())
f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\" % (
cmp.upper()))
f.writeln(" const char *_lh = lh; \\")
f.writeln(" const char *_rh = rh; \\")
f.writeln(" if (!(strcmp(_lh, _rh) %s 0)) { \\" % op)
f.writeln(" __pretty_assert_print( \\")
f.writeln(" __FILE__, __LINE__, \\")
f.writeln(" __pretty_assert_str, \"%s\", \\"
% cmp)
f.writeln(" __pretty_assert_str, \"%s\", \\" % cmp)
f.writeln(" _lh, strlen(_lh), \\")
f.writeln(" _rh, strlen(_rh)); \\")
f.writeln(" __builtin_trap(); \\")
@@ -206,11 +203,11 @@ def write_header(f, limit=LIMIT):
def mkassert(type, cmp, lh, rh, size=None):
if size is not None:
return ("__PRETTY_ASSERT_%s_%s(%s, %s, %s)"
% (type.upper(), cmp.upper(), lh, rh, size))
return ("__PRETTY_ASSERT_%s_%s(%s, %s, %s)" % (
type.upper(), cmp.upper(), lh, rh, size))
else:
return ("__PRETTY_ASSERT_%s_%s(%s, %s)"
% (type.upper(), cmp.upper(), lh, rh))
return ("__PRETTY_ASSERT_%s_%s(%s, %s)" % (
type.upper(), cmp.upper(), lh, rh))
def mkunreachable():
return "__PRETTY_ASSERT_UNREACHABLE()"
@@ -542,8 +539,8 @@ if __name__ == "__main__":
'-l', '--limit',
type=lambda x: int(x, 0),
default=LIMIT,
help="Maximum number of characters to display in strcmp and memcmp. "
"Defaults to %r." % LIMIT)
help="Maximum number of characters to display in strcmp and "
"memcmp. Defaults to %r." % LIMIT)
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))
+2
View File
@@ -2,6 +2,7 @@
import subprocess as sp
def main(args):
with open(args.disk, 'rb') as f:
f.seek(args.block * args.block_size)
@@ -12,6 +13,7 @@ def main(args):
print("%-8s %-s" % ('off', 'data'))
return sp.run(['xxd', '-g1', '-'], input=block).returncode
if __name__ == "__main__":
import argparse
import sys
+9 -6
View File
@@ -5,6 +5,7 @@ import binascii
import sys
import itertools as it
TAG_TYPES = {
'splice': (0x700, 0x400),
'create': (0x7ff, 0x401),
@@ -104,8 +105,9 @@ class Tag:
try:
if ' ' in type:
type1, type3 = type.split()
return (self.is_(type1) and
(self.type & ~TAG_TYPES[type1][0]) == int(type3, 0))
return (self.is_(type1)
and (self.type & ~TAG_TYPES[type1][0])
== int(type3, 0))
return self.type == int(type, 0)
@@ -286,16 +288,16 @@ class MetadataPair:
gdiff = 0
for tag in reversed(self.log):
if (gmask.id != 0 and tag.is_('splice') and
tag.id <= gtag.id - gdiff):
if (gmask.id != 0 and tag.is_('splice')
and tag.id <= gtag.id - gdiff):
if tag.is_('create') and tag.id == gtag.id - gdiff:
# creation point
break
gdiff += tag.schunk
if ((int(gmask) & int(tag)) ==
(int(gmask) & int(gtag.chid(gtag.id - gdiff)))):
if ((int(gmask) & int(tag))
== (int(gmask) & int(gtag.chid(gtag.id - gdiff)))):
if tag.size == 0x3ff:
# deleted
break
@@ -377,6 +379,7 @@ def main(args):
return 0 if mdir else 1
if __name__ == "__main__":
import argparse
import sys
+10 -4
View File
@@ -7,6 +7,7 @@ import io
import itertools as it
from readmdir import Tag, MetadataPair
def main(args):
superblock = None
gstate = b'\0\0\0\0\0\0\0\0\0\0\0\0'
@@ -103,10 +104,13 @@ def main(args):
version = ('?', '?')
if superblock:
version = tuple(reversed(
struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff'))))
print("%-47s%s" % ("littlefs v%s.%s" % version,
struct.unpack('<HH',
superblock[1].data[0:4].ljust(4, b'\xff'))))
print("%-47s%s" % (
"littlefs v%s.%s" % version,
"data (truncated, if it fits)"
if not any([args.no_truncate, args.log, args.all]) else ""))
if not any([args.no_truncate, args.log, args.all])
else ""))
# print gstate
print("gstate 0x%s" % ''.join('%02x' % c for c in gstate))
@@ -159,11 +163,13 @@ def main(args):
return errcode
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Dump semantic info about the metadata tree in littlefs")
description="Dump semantic info about the metadata tree in "
"littlefs")
parser.add_argument('disk',
help="File representing the block device.")
parser.add_argument('block_size', type=lambda x: int(x, 0),
+33 -28
View File
@@ -18,7 +18,6 @@ import os
import re
# integer fields
class RInt(co.namedtuple('RInt', 'x')):
__slots__ = ()
@@ -179,8 +178,8 @@ def collect(ci_paths, *,
if (not args.get('quiet')
and 'static' not in type
and 'bounded' not in type):
print("warning: "
"found non-static stack for %s (%s, %s)" % (
print("warning: found non-static stack "
"for %s (%s, %s)" % (
function, type, size))
_, _, _, targets = callgraph[info['title']]
callgraph[info['title']] = (
@@ -199,8 +198,7 @@ def collect(ci_paths, *,
continue
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(s_file) == os.path.abspath(s)
if not any(os.path.abspath(s_file) == os.path.abspath(s)
for s in sources):
continue
else:
@@ -339,12 +337,13 @@ def table(Result, results, diff_results=None, *,
r = max(results_,
key=lambda r: tuple(
tuple(
(getattr(r, k),)
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])
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])))
@@ -378,7 +377,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -389,9 +389,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -399,8 +402,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -484,10 +486,13 @@ def table(Result, results, diff_results=None, *,
names_.sort(
key=lambda n: tuple(
(getattr(table_[n], k),)
if getattr(table_.get(n), k, None) is not None
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])),
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_):
@@ -509,8 +514,7 @@ def table(Result, results, diff_results=None, *,
# recurse?
if depth_ > 1:
recurse(
r.children,
recurse(r.children,
depth_-1,
seen | {name},
(prefixes[2+is_last] + "|-> ",
@@ -530,8 +534,7 @@ def table(Result, results, diff_results=None, *,
# recursive entries
if name in table and depth > 1:
recurse(
table[name].children,
recurse(table[name].children,
depth-1,
{name},
("|-> ",
@@ -626,14 +629,16 @@ def main(ci_paths,
writer = csv.DictWriter(f,
(by if by is not None else StackResult._by)
+ [k for k in (
fields if fields is not None else StackResult._fields)])
fields if fields is not None
else StackResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else StackResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else StackResult._fields)})
fields if fields is not None
else StackResult._fields)})
# find previous results?
if args.get('diff'):
@@ -757,8 +762,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
@@ -768,8 +773,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Depth of function calls to show. 0 shows all calls unless we "
"find a cycle. Defaults to 0.")
help="Depth of function calls to show. 0 shows all calls unless "
"we find a cycle. Defaults to 0.")
parser.add_argument(
'-t', '--hot',
nargs='?',
+19 -14
View File
@@ -23,7 +23,6 @@ import subprocess as sp
OBJDUMP_PATH = ['objdump']
# integer fields
class RInt(co.namedtuple('RInt', 'x')):
__slots__ = ()
@@ -100,7 +99,9 @@ class RInt(co.namedtuple('RInt', 'x')):
return self.__class__(self.x * other.x)
# struct size results
class StructResult(co.namedtuple('StructResult', ['file', 'struct', 'size'])):
class StructResult(co.namedtuple('StructResult', [
'file', 'struct',
'size'])):
_by = ['file', 'struct']
_fields = ['size']
_sort = ['size']
@@ -233,8 +234,7 @@ def collect(obj_paths, *,
for r in results_:
# ignore filtered sources
if sources is not None:
if not any(
os.path.abspath(r.file) == os.path.abspath(s)
if not any(os.path.abspath(r.file) == os.path.abspath(s)
for s in sources):
continue
else:
@@ -335,7 +335,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -346,9 +347,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -356,8 +360,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -516,14 +519,16 @@ def main(obj_paths, *,
writer = csv.DictWriter(f,
(by if by is not None else StructResult._by)
+ [k for k in (
fields if fields is not None else StructResult._fields)])
fields if fields is not None
else StructResult._fields)])
writer.writeheader()
for r in results:
writer.writerow(
{k: getattr(r, k) for k in (
by if by is not None else StructResult._by)}
| {k: getattr(r, k) for k in (
fields if fields is not None else StructResult._fields)})
fields if fields is not None
else StructResult._fields)})
# find previous results?
if args.get('diff'):
@@ -643,8 +648,8 @@ if __name__ == "__main__":
'-F', '--source',
dest='sources',
action='append',
help="Only consider definitions in this file. Defaults to anything "
"in the current directory.")
help="Only consider definitions in this file. Defaults to "
"anything in the current directory.")
parser.add_argument(
'--everything',
action='store_true',
+19 -15
View File
@@ -302,16 +302,14 @@ def infer(fields_, results,
defines=[]):
# if by not specified, guess it's anything not in fields/renames/defines
if by is None:
by = [
k for k in fields_
by = [k for k in fields_
if k not in (fields or [])
and not any(k == old_k for _, old_k in renames)
and not any(k == k_ for k_, _ in defines)]
# if fields not specified, guess it's anything not in by/renames/defines
if fields is None:
fields = [
k for k in fields_
fields = [k for k in fields_
if k not in (by or [])
and not any(k == old_k for _, old_k in renames)
and not any(k == k_ for k_, _ in defines)]
@@ -468,7 +466,8 @@ def table(Result, results, diff_results=None, *,
# sort again, now with diff info, note that python's sort is stable
names.sort()
if diff_results is not None:
names.sort(key=lambda n: tuple(
names.sort(
key=lambda n: tuple(
types[k].ratio(
getattr(table.get(n), k, None),
getattr(diff_table.get(n), k, None))
@@ -479,9 +478,12 @@ def table(Result, results, diff_results=None, *,
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])),
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))
@@ -489,8 +491,7 @@ def table(Result, results, diff_results=None, *,
lines = []
# header
header = [
'%s%s' % (
header = ['%s%s' % (
','.join(by),
' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table),
@@ -702,7 +703,8 @@ def main(csv_paths, *,
for r in results:
# note we need to go through getattr to resolve lazy fields
writer.writerow({
k: getattr(r, k) for k in Result._by + Result._fields})
k: getattr(r, k)
for k in Result._by + Result._fields})
# find previous results?
if args.get('diff'):
@@ -773,7 +775,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Group by this field. Can rename fields with new_name=old_name.")
help="Group by this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-f', '--field',
dest='fields',
@@ -784,7 +787,8 @@ if __name__ == "__main__":
tuple(v.strip() for v in vs.split(','))
if vs is not None else ())
)(*x.split('=', 1)),
help="Show this field. Can rename fields with new_name=old_name.")
help="Show this field. Can rename fields with "
"new_name=old_name.")
parser.add_argument(
'-D', '--define',
dest='defines',
@@ -794,8 +798,8 @@ if __name__ == "__main__":
k.strip(),
{v.strip() for v in vs.split(',')})
)(*x.split('=', 1)),
help="Only include results where this field is this value. May include "
"comma-separated options.")
help="Only include results where this field is this value. May "
"include comma-separated options.")
class AppendSort(argparse.Action):
def __call__(self, parser, namespace, value, option):
if namespace.sort is None:
+4 -3
View File
@@ -157,7 +157,8 @@ if __name__ == "__main__":
import sys
import argparse
parser = argparse.ArgumentParser(
description="Efficiently displays the last n lines of a file/pipe.",
description="Efficiently displays the last n lines of a "
"file/pipe.",
allow_abbrev=False)
parser.add_argument(
'path',
@@ -168,8 +169,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Show this many lines of history. 0 uses the terminal height. "
"Defaults to 5.")
help="Show this many lines of history. 0 uses the terminal "
"height. Defaults to 5.")
parser.add_argument(
'-z', '--cat',
action='store_true',
+84 -75
View File
@@ -198,7 +198,8 @@ class TestSuite:
case_linenos, case_linenos[1:],
fillvalue=(float('inf'), None)):
code_lineno = min(
(l for l in code_linenos if l >= lineno and l < nlineno),
(l for l in code_linenos
if l >= lineno and l < nlineno),
default=None)
cases[name]['lineno'] = lineno
cases[name]['code_lineno'] = code_lineno
@@ -229,7 +230,8 @@ class TestSuite:
self.cases = []
for name, case in cases.items():
self.cases.append(TestCase(config={
self.cases.append(TestCase(
config={
'name': name,
'path': path + (':%d' % case['lineno']
if 'lineno' in case else ''),
@@ -386,23 +388,21 @@ def compile(test_paths, **args):
for k, vs in sorted(permutation.items()):
f.writeln('intmax_t __test__%s__%s__%d('
'__attribute__((unused)) void *data, '
'size_t i) {'
% (case.name, k, i))
'size_t i) {' % (
case.name, k, i))
j = 0
for v in vs:
# generate range
if isinstance(v, range):
f.writeln(
4*' '+'if (i < %d) '
'return (i-%d)*%d + %d;'
% (j+len(v), j, v.step, v.start))
f.writeln(4*' '+'if (i < %d) '
'return (i-%d)*%d + %d;' % (
j+len(v), j, v.step, v.start))
j += len(v)
# translate index to define
else:
f.writeln(
4*' '+'if (i == %d) '
'return %s;'
% (j, v))
f.writeln(4*' '+'if (i == %d) '
'return %s;' % (
j, v))
j += 1;
f.writeln(4*' '+'__builtin_unreachable();')
@@ -411,8 +411,8 @@ def compile(test_paths, **args):
# create case if function
if suite.if_ or case.if_:
f.writeln('bool __test__%s__if(void) {'
% (case.name))
f.writeln('bool __test__%s__if(void) {' % (
case.name))
for if_ in it.chain(suite.if_, case.if_):
f.writeln(4*' '+'if (!(%s)) return false;' % (
'true' if if_ is True
@@ -424,16 +424,17 @@ def compile(test_paths, **args):
# create case run function
f.writeln('void __test__%s__run('
'__attribute__((unused)) struct lfs_config *CFG) {'
% (case.name))
'__attribute__((unused)) '
'struct lfs_config *CFG) {' % (
case.name))
f.writeln(4*' '+'// test case %s' % case.name)
if case.code_lineno is not None:
f.writeln(4*' '+'#line %d "%s"'
% (case.code_lineno, suite.path))
f.writeln(4*' '+'#line %d "%s"' % (
case.code_lineno, suite.path))
f.write(case.code)
if case.code_lineno is not None:
f.writeln(4*' '+'#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln(4*' '+'#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln('}')
f.writeln()
@@ -453,19 +454,19 @@ def compile(test_paths, **args):
# write any suite defines
if suite.defines:
for define in sorted(suite.defines):
f.writeln('__attribute__((weak)) intmax_t %s;'
% define)
f.writeln('__attribute__((weak)) intmax_t %s;' % (
define))
f.writeln()
# write any suite code
if suite.code is not None and suite.in_ is None:
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (suite.code_lineno, suite.path))
f.writeln('#line %d "%s"' % (
suite.code_lineno, suite.path))
f.write(suite.code)
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln('#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln()
# create case functions
@@ -476,15 +477,15 @@ def compile(test_paths, **args):
for i, permutation in enumerate(case.permutations):
for k, vs in sorted(permutation.items()):
f.writeln('extern intmax_t __test__%s__%s__%d('
'void *data, size_t i);'
% (case.name, k, i))
'void *data, size_t i);' % (
case.name, k, i))
if suite.if_ or case.if_:
f.writeln('extern bool __test__%s__if('
'void);'
% (case.name))
'void);' % (
case.name))
f.writeln('extern void __test__%s__run('
'struct lfs_config *CFG);'
% (case.name))
'struct lfs_config *CFG);' % (
case.name))
f.writeln()
# write any ifdef epilogues
@@ -494,12 +495,12 @@ def compile(test_paths, **args):
f.writeln()
# create suite struct
f.writeln('const struct test_suite __test__%s__suite = {'
% suite.name)
f.writeln('const struct test_suite __test__%s__suite = {' % (
suite.name))
f.writeln(4*' '+'.name = "%s",' % suite.name)
f.writeln(4*' '+'.path = "%s",' % suite.path)
f.writeln(4*' '+'.flags = %s,'
% (' | '.join(filter(None, [
f.writeln(4*' '+'.flags = %s,' % (
' | '.join(filter(None, [
'TEST_INTERNAL' if suite.internal else None,
'TEST_REENTRANT' if suite.reentrant else None,
'TEST_FUZZ' if suite.fuzz else None]))
@@ -510,8 +511,8 @@ def compile(test_paths, **args):
if suite.defines:
f.writeln(4*' '+'.defines = (const test_define_t[]){')
for k in sorted(suite.defines):
f.writeln(8*' '+'{"%s", &%s, NULL, NULL, 0},'
% (k, k))
f.writeln(8*' '+'{"%s", &%s, NULL, NULL, 0},' % (
k, k))
f.writeln(4*' '+'},')
f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
for ifdef in suite.ifdef:
@@ -523,11 +524,14 @@ def compile(test_paths, **args):
f.writeln(8*' '+'{')
f.writeln(12*' '+'.name = "%s",' % case.name)
f.writeln(12*' '+'.path = "%s",' % case.path)
f.writeln(12*' '+'.flags = %s,'
% (' | '.join(filter(None, [
'TEST_INTERNAL' if case.internal else None,
'TEST_REENTRANT' if case.reentrant else None,
'TEST_FUZZ' if case.fuzz else None]))
f.writeln(12*' '+'.flags = %s,' % (
' | '.join(filter(None, [
'TEST_INTERNAL' if case.internal
else None,
'TEST_REENTRANT' if case.reentrant
else None,
'TEST_FUZZ' if case.fuzz
else None]))
or 0))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#ifdef %s' % ifdef)
@@ -535,15 +539,16 @@ def compile(test_paths, **args):
if case.defines:
f.writeln(12*' '+'.defines'
' = (const test_define_t*)'
'(const test_define_t[][%d]){'
% (len(suite.defines)))
'(const test_define_t[][%d]){' % (
len(suite.defines)))
for i, permutation in enumerate(case.permutations):
f.writeln(16*' '+'{')
for k, vs in sorted(permutation.items()):
f.writeln(20*' '+'[%d] = {'
'"%s", &%s, '
'__test__%s__%s__%d, NULL, %d},'
% (sorted(suite.defines).index(k),
'__test__%s__%s__%d, '
'NULL, %d},' % (
sorted(suite.defines).index(k),
k, k, case.name, k, i,
sum(len(v)
if isinstance(v, range)
@@ -551,13 +556,13 @@ def compile(test_paths, **args):
for v in vs)))
f.writeln(16*' '+'},')
f.writeln(12*' '+'},')
f.writeln(12*' '+'.permutations = %d,'
% len(case.permutations))
f.writeln(12*' '+'.permutations = %d,' % (
len(case.permutations)))
if suite.if_ or case.if_:
f.writeln(12*' '+'.if_ = __test__%s__if,'
% (case.name))
f.writeln(12*' '+'.run = __test__%s__run,'
% (case.name))
f.writeln(12*' '+'.if_ = __test__%s__if,' % (
case.name))
f.writeln(12*' '+'.run = __test__%s__run,' % (
case.name))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#endif')
f.writeln(8*' '+'},')
@@ -586,8 +591,8 @@ def compile(test_paths, **args):
for define in case.defines})
if defines:
for define in sorted(defines):
f.writeln('__attribute__((weak)) intmax_t %s;'
% define)
f.writeln('__attribute__((weak)) intmax_t %s;' % (
define))
f.writeln()
# write any internal tests
@@ -601,12 +606,12 @@ def compile(test_paths, **args):
# any suite code
if suite.isin(args['source']):
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (suite.code_lineno, suite.path))
f.writeln('#line %d "%s"' % (
suite.code_lineno, suite.path))
f.write(suite.code)
if suite.code_lineno is not None:
f.writeln('#line %d "%s"'
% (f.lineno+1, args['output']))
f.writeln('#line %d "%s"' % (
f.lineno+1, args['output']))
f.writeln()
# any case functions
@@ -627,7 +632,8 @@ def compile(test_paths, **args):
# will be linked
for suite in suites:
f.writeln('extern const struct test_suite '
'__test__%s__suite;' % suite.name)
'__test__%s__suite;' % (
suite.name))
f.writeln()
f.writeln('__attribute__((weak))')
@@ -786,8 +792,7 @@ def find_perms(runner, test_ids=[], **args):
expected_suite_perms.get(suite, 0)
+ expected_case_perms.get(case, 0))
return (
case_suites,
return (case_suites,
expected_suite_perms,
expected_case_perms,
expected_perms,
@@ -1240,8 +1245,7 @@ def run_stage(name, runner, test_ids, stdout_, trace_, output_, **args):
for r in runners:
r.join()
return (
expected_perms,
return (expected_perms,
passed_perms,
failed_perms,
powerlosses,
@@ -1367,7 +1371,8 @@ def run(runner, test_ids=[], **args):
'\x1b[01;31m' if args['color'] else '',
'\x1b[m' if args['color'] else '',
failure.id,
' (%s)' % ', '.join('%s=%s' % (k,v) for k,v in defines.items())
' (%s)' % ', '.join('%s=%s' % (k,v)
for k,v in defines.items())
if defines else ''))
if failure.stdout:
@@ -1519,7 +1524,8 @@ if __name__ == "__main__":
'-R', '--runner',
type=lambda x: x.split(),
default=RUNNER_PATH,
help="Test runner to use for testing. Defaults to %r." % RUNNER_PATH)
help="Test runner to use for testing. Defaults to "
"%r." % RUNNER_PATH)
test_parser.add_argument(
'-Y', '--summary',
action='store_true',
@@ -1588,7 +1594,8 @@ if __name__ == "__main__":
help="Sample trace output at this frequency in hz.")
test_parser.add_argument(
'-O', '--stdout',
help="Direct stdout to this file. Note stderr is already merged here.")
help="Direct stdout to this file. Note stderr is already merged "
"here.")
test_parser.add_argument(
'-o', '--output',
help="CSV file to store results.")
@@ -1606,7 +1613,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Number of parallel runners to run. 0 runs one runner per core.")
help="Number of parallel runners to run. 0 runs one runner per "
"core.")
test_parser.add_argument(
'-k', '--keep-going',
action='store_true',
@@ -1687,12 +1695,12 @@ if __name__ == "__main__":
"Defaults to %r." % VALGRIND_PATH)
test_parser.add_argument(
'-p', '--perf',
help="Run under Linux's perf to sample performance counters, writing "
"samples to this file.")
help="Run under Linux's perf to sample performance counters, "
"writing samples to this file.")
test_parser.add_argument(
'--perf-freq',
help="perf sampling frequency. This is passed directly to the perf "
"script.")
help="perf sampling frequency. This is passed directly to the "
"perf script.")
test_parser.add_argument(
'--perf-period',
help="perf sampling period. This is passed directly to the perf "
@@ -1705,12 +1713,13 @@ if __name__ == "__main__":
'--perf-script',
type=lambda x: x.split(),
default=PERF_SCRIPT,
help="Path to the perf script to use. Defaults to %r." % PERF_SCRIPT)
help="Path to the perf script to use. Defaults to "
"%r." % PERF_SCRIPT)
test_parser.add_argument(
'--perf-path',
type=lambda x: x.split(),
help="Path to the perf executable, may include flags. This is passed "
"directly to the perf script")
help="Path to the perf executable, may include flags. This is "
"passed directly to the perf script")
# compilation flags
comp_parser = parser.add_argument_group('compilation options')
+15 -11
View File
@@ -363,8 +363,7 @@ class Pixel(int):
f = [colors[3]]
if wear:
w = min(
self.worn(
w = min(self.worn(
max_wear,
block_cycles=block_cycles,
wear_chars=wear_chars),
@@ -793,7 +792,8 @@ def main(path='-', *,
bmap.resize(
# scale if we're printing with dots or braille
width=2*width_ if braille else width_,
height=max(1,
height=max(
1,
4*height_ if braille
else 2*height_ if dots
else height_))
@@ -811,7 +811,8 @@ def main(path='-', *,
'(?:'
'block_size=(?P<block_size>\w+)'
'|' 'block_count=(?P<block_count>\w+)'
'|' '.*?' ')*' '\)'
'|' '.*?' ')*'
'\)'
'|' '(?P<read>read)\('
'\s*(?P<read_ctx>\w+)' '\s*,'
'\s*(?P<read_block>\w+)' '\s*,'
@@ -829,7 +830,8 @@ def main(path='-', *,
'\s*(?P<erase_block>\w+)'
'\s*\(\s*(?P<erase_size>\w+)\s*\)' '\s*\)'
'|' '(?P<sync>sync)\('
'\s*(?P<sync_ctx>\w+)' '\s*\)' ')\s*$')
'\s*(?P<sync_ctx>\w+)' '\s*\)'
')\s*$')
def parse(line):
nonlocal bmap
nonlocal readed
@@ -1074,7 +1076,8 @@ if __name__ == "__main__":
parser.add_argument(
'-c', '--block-cycles',
type=lambda x: int(x, 0),
help="Assumed maximum number of erase cycles when measuring wear.")
help="Assumed maximum number of erase cycles when measuring "
"wear.")
parser.add_argument(
'-@', '--block',
nargs='?',
@@ -1130,8 +1133,8 @@ if __name__ == "__main__":
parser.add_argument(
'-⣿', '--braille',
action='store_true',
help="Use 2x4 unicode braille characters. Note that braille characters "
"sometimes suffer from inconsistent widths.")
help="Use 2x4 unicode braille characters. Note that braille "
"characters sometimes suffer from inconsistent widths.")
parser.add_argument(
'--chars',
help="Characters to use for read, prog, erase, noop operations.")
@@ -1164,8 +1167,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Show this many lines of history. 0 uses the terminal height. "
"Defaults to 5.")
help="Show this many lines of history. 0 uses the terminal "
"height. Defaults to 5.")
parser.add_argument(
'-^', '--head',
action='store_true',
@@ -1189,7 +1192,8 @@ if __name__ == "__main__":
parser.add_argument(
'-s', '--sleep',
type=float,
help="Time in seconds to sleep between reads, coalescing operations.")
help="Time in seconds to sleep between reads, coalescing "
"operations.")
parser.add_argument(
'-k', '--keep-open',
action='store_true',
+5 -4
View File
@@ -261,8 +261,9 @@ if __name__ == "__main__":
import sys
import argparse
parser = argparse.ArgumentParser(
description="Traditional watch command, but with higher resolution "
"updates and a bit different options/output format.",
description="Traditional watch command, but with higher "
"resolution updates and a bit different options/output "
"format.",
allow_abbrev=False)
parser.add_argument(
'command',
@@ -273,8 +274,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: int(x, 0),
const=0,
help="Show this many lines of history. 0 uses the terminal height. "
"Defaults to 0.")
help="Show this many lines of history. 0 uses the terminal "
"height. Defaults to 0.")
parser.add_argument(
'-^', '--head',
action='store_true',