mirror of
https://github.com/littlefs-project/littlefs.git
synced 2026-04-09 04:11:03 +00:00
Limit ./scripts/structs.py to report structs in local .h files
This requires parsing an additional section of the dwarfinfo (--dwarf=rawlines) to get the declaration file info. --- Interpreting the results of ./scripts/structs.py reporting is a bit more complicated than other scripts, structs aren't used in a consistent manner so the cost of a large struct depends on the context in which it is used. But that being said, there really isn't much reason to report internal-only structs. These structs really only exist for type-checking in internal algorithms, and their cost will end up reflected in other RAM measurements, either stack, heap, or other.
This commit is contained in:
@@ -16,16 +16,48 @@ import collections as co
|
|||||||
OBJ_PATHS = ['*.o']
|
OBJ_PATHS = ['*.o']
|
||||||
|
|
||||||
def collect(paths, **args):
|
def collect(paths, **args):
|
||||||
results = co.defaultdict(lambda: 0)
|
decl_pattern = re.compile(
|
||||||
pattern = re.compile(
|
'^\s+(?P<no>[0-9]+)'
|
||||||
|
'\s+(?P<dir>[0-9]+)'
|
||||||
|
'\s+.*'
|
||||||
|
'\s+(?P<file>[^\s]+)$')
|
||||||
|
struct_pattern = re.compile(
|
||||||
'^(?:.*DW_TAG_(?P<tag>[a-z_]+).*'
|
'^(?:.*DW_TAG_(?P<tag>[a-z_]+).*'
|
||||||
'|^.*DW_AT_name.*:\s*(?P<name>[^:\s]+)\s*'
|
'|^.*DW_AT_name.*:\s*(?P<name>[^:\s]+)\s*'
|
||||||
|
'|^.*DW_AT_decl_file.*:\s*(?P<decl>[0-9]+)\s*'
|
||||||
'|^.*DW_AT_byte_size.*:\s*(?P<size>[0-9]+)\s*)$')
|
'|^.*DW_AT_byte_size.*:\s*(?P<size>[0-9]+)\s*)$')
|
||||||
|
|
||||||
|
results = co.defaultdict(lambda: 0)
|
||||||
for path in paths:
|
for path in paths:
|
||||||
|
# find decl, we want to filter by structs in .h files
|
||||||
|
decls = {}
|
||||||
|
# note objdump-tool may contain extra args
|
||||||
|
cmd = args['objdump_tool'] + ['--dwarf=rawline', path]
|
||||||
|
if args.get('verbose'):
|
||||||
|
print(' '.join(shlex.quote(c) for c in cmd))
|
||||||
|
proc = sp.Popen(cmd,
|
||||||
|
stdout=sp.PIPE,
|
||||||
|
stderr=sp.PIPE if not args.get('verbose') else None,
|
||||||
|
universal_newlines=True,
|
||||||
|
errors='replace')
|
||||||
|
for line in proc.stdout:
|
||||||
|
# find file numbers
|
||||||
|
m = decl_pattern.match(line)
|
||||||
|
if m:
|
||||||
|
decls[int(m.group('no'))] = (
|
||||||
|
m.group('file'),
|
||||||
|
int(m.group('dir')))
|
||||||
|
proc.wait()
|
||||||
|
if proc.returncode != 0:
|
||||||
|
if not args.get('verbose'):
|
||||||
|
for line in proc.stderr:
|
||||||
|
sys.stdout.write(line)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
# collect structs as we parse dwarf info
|
# collect structs as we parse dwarf info
|
||||||
found = False
|
found = False
|
||||||
name = None
|
name = None
|
||||||
|
decl = None
|
||||||
size = None
|
size = None
|
||||||
|
|
||||||
# note objdump-tool may contain extra args
|
# note objdump-tool may contain extra args
|
||||||
@@ -39,16 +71,22 @@ def collect(paths, **args):
|
|||||||
errors='replace')
|
errors='replace')
|
||||||
for line in proc.stdout:
|
for line in proc.stdout:
|
||||||
# state machine here to find structs
|
# state machine here to find structs
|
||||||
m = pattern.match(line)
|
m = struct_pattern.match(line)
|
||||||
if m:
|
if m:
|
||||||
if m.group('tag'):
|
if m.group('tag'):
|
||||||
if name is not None and size is not None:
|
if (name is not None
|
||||||
results[(path, name)] = size
|
and decl is not None
|
||||||
|
and size is not None):
|
||||||
|
decl_file, decl_dir = decls.get(decl, ('', 0))
|
||||||
|
results[(path, name)] = (size, decl_file, decl_dir)
|
||||||
found = (m.group('tag') == 'structure_type')
|
found = (m.group('tag') == 'structure_type')
|
||||||
name = None
|
name = None
|
||||||
|
decl = None
|
||||||
size = None
|
size = None
|
||||||
elif found and m.group('name'):
|
elif found and m.group('name'):
|
||||||
name = m.group('name')
|
name = m.group('name')
|
||||||
|
elif found and name and m.group('decl'):
|
||||||
|
decl = int(m.group('decl'))
|
||||||
elif found and name and m.group('size'):
|
elif found and name and m.group('size'):
|
||||||
size = int(m.group('size'))
|
size = int(m.group('size'))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
@@ -59,18 +97,25 @@ def collect(paths, **args):
|
|||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
flat_results = []
|
flat_results = []
|
||||||
for (file, struct), size in results.items():
|
for (path, struct), (size, decl_file, decl_dir) in results.items():
|
||||||
# map to source files
|
# map to source files
|
||||||
if args.get('build_dir'):
|
if args.get('build_dir'):
|
||||||
file = re.sub('%s/*' % re.escape(args['build_dir']), '', file)
|
path = re.sub('%s/*' % re.escape(args['build_dir']), '', path)
|
||||||
|
# only include structs declared in header files in the current
|
||||||
|
# directory, ignore internal-only # structs (these are represented
|
||||||
|
# in other measurements)
|
||||||
|
if not args.get('everything'):
|
||||||
|
if not (decl_file.endswith('.h') and decl_dir == 0):
|
||||||
|
continue
|
||||||
# replace .o with .c, different scripts report .o/.c, we need to
|
# replace .o with .c, different scripts report .o/.c, we need to
|
||||||
# choose one if we want to deduplicate csv files
|
# choose one if we want to deduplicate csv files
|
||||||
file = re.sub('\.o$', '.c', file)
|
path = re.sub('\.o$', '.c', path)
|
||||||
|
|
||||||
flat_results.append((file, struct, size))
|
flat_results.append((path, struct, size))
|
||||||
|
|
||||||
return flat_results
|
return flat_results
|
||||||
|
|
||||||
|
|
||||||
def main(**args):
|
def main(**args):
|
||||||
def openio(path, mode='r'):
|
def openio(path, mode='r'):
|
||||||
if path == '-':
|
if path == '-':
|
||||||
|
|||||||
Reference in New Issue
Block a user