Skip to content

Commit d0ae88d

Browse files
andy31415andreilitvinrestyled-commits
authored
Minor fixes for nm mapping (project-chip#37873)
* Extract shorten name and add unit tests * Fix ids * Restyled by autopep8 * Add glob support for symbols, to quickly figure out sizes * Update title --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Restyled.io <commits@restyled.io>
1 parent a4530cb commit d0ae88d

File tree

1 file changed

+65
-31
lines changed

1 file changed

+65
-31
lines changed

scripts/tools/file_size_from_nm.py

+65-31
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
# pandas
4242
# plotly
4343

44+
import fnmatch
4445
import logging
4546
import re
4647
import subprocess
@@ -362,6 +363,41 @@ def test_tree_display_name():
362363
) == ["(anonymous namespace)", "AccessControlAttribute", "Read(args)"]
363364

364365

366+
def shorten_name(full_name: str) -> str:
367+
"""
368+
Remove namespaces, but keep template parts
369+
370+
This tries to convert:
371+
foo::bar::baz(int, double) -> baz(int, double)
372+
foo::bar::baz<x::y>(int, double) -> baz<x::y>(int, double)
373+
foo::bar::baz(some::ns::bit, double) -> baz(some::ns::bit, double)
374+
foo::bar::baz<x::y>(some::ns::bit, double) -> baz<x::y>(some::ns::bit, double)
375+
376+
Remove all before '::', however '::' found before the first of < or (
377+
"""
378+
limit1 = full_name.find('<')
379+
limit2 = full_name.find('(')
380+
if limit1 >= 0 and limit1 < limit2:
381+
limit = limit1
382+
else:
383+
limit = limit2
384+
separate_idx = full_name.rfind('::', 0, limit)
385+
if separate_idx > 0:
386+
short_name = full_name[separate_idx+2:]
387+
else:
388+
short_name = full_name
389+
return short_name
390+
391+
392+
def test_shorten_name():
393+
assert shorten_name("foo::bar::baz(int, double)") == "baz(int, double)"
394+
assert shorten_name("foo::bar::baz<x::y>(int, double)") == "baz<x::y>(int, double)"
395+
assert shorten_name("foo::bar::baz(some::ns::bit, double)") == "baz(some::ns::bit, double)"
396+
assert shorten_name("foo::bar::baz<x::y>(some::ns::bit, double)") == "baz<x::y>(some::ns::bit, double)"
397+
assert shorten_name("chip::app:EnabledEndpointsWithServerCluster::EnsureMatchingEndpoint()") == "EnsureMatchingEndpoint()"
398+
assert shorten_name("void chip::app:EnabledEndpointsWithServerCluster::operator++()") == "operator++()"
399+
400+
365401
def build_treemap(
366402
name: str,
367403
symbols: list[Symbol],
@@ -381,7 +417,7 @@ def build_treemap(
381417
root = f"FILE: {name}"
382418
if zoom:
383419
root = root + f" (FILTER: {zoom})"
384-
data: dict[str, list] = dict(name=[root], parent=[""], size=[0], hover=[""], name_with_size=[""], short_name=[""])
420+
data: dict[str, list] = dict(name=[root], parent=[""], size=[0], hover=[""], name_with_size=[""], short_name=[""], id=[root])
385421

386422
known_parents: set[str] = set()
387423
total_sizes: dict = {}
@@ -410,15 +446,19 @@ def build_treemap(
410446
continue
411447

412448
partial = ""
449+
path = ""
413450
for name in tree_name[:-1]:
414451
if not partial:
415452
next_value = name
416453
else:
417454
next_value = partial + separator + name
455+
parent_path = path if partial else root
456+
path = path + separator + name
418457
if next_value not in known_parents:
419458
known_parents.add(next_value)
420459
data["name"].append(next_value)
421-
data["parent"].append(partial if partial else root)
460+
data["id"].append(path)
461+
data["parent"].append(parent_path)
422462
data["size"].append(0)
423463
data["hover"].append(next_value)
424464
data["name_with_size"].append("")
@@ -428,7 +468,8 @@ def build_treemap(
428468

429469
# the name MUST be added
430470
data["name"].append(cxxfilt.demangle(symbol.name))
431-
data["parent"].append(partial if partial else root)
471+
data["id"].append(symbol.name)
472+
data["parent"].append(path if partial else root)
432473
data["size"].append(symbol.size)
433474
data["hover"].append(f"{symbol.name} of type {symbol.symbol_type}")
434475
data["name_with_size"].append("")
@@ -446,27 +487,7 @@ def build_treemap(
446487
else:
447488
# When using object files, the paths hare are the full "foo::bar::....::method"
448489
# so clean them up a bit
449-
short_name = data["short_name"][idx]
450-
451-
# remove namespaces, but keep template parts
452-
# This tries to convert:
453-
# foo::bar::baz(int, double) -> baz(int, double)
454-
# foo::bar::baz<x::y>(int, double) -> baz<x::y>(int, double)
455-
# foo::bar::baz(some::ns:bit, double) -> baz(some::ns::bit, double)
456-
# foo::bar::baz<x::y>(some::ns:bit, double) -> baz<x::y>(some::ns::bit, double)
457-
#
458-
# Remove all before '::', however '::' found before the first of < or (
459-
#
460-
limit1 = short_name.find('<')
461-
limit2 = short_name.find('(')
462-
if limit1 >= 0 and limit1 < limit2:
463-
limit = limit1
464-
else:
465-
limit = limit2
466-
separate_idx = short_name.rfind('::', 0, limit)
467-
if separate_idx:
468-
short_name = short_name[separate_idx+2:]
469-
490+
short_name = shorten_name(data["short_name"][idx])
470491
data["name_with_size"][idx] = f"{short_name}: {data["size"][idx]}"
471492

472493
extra_args = {}
@@ -477,7 +498,7 @@ def build_treemap(
477498
fig = figure_generator(
478499
data,
479500
names="name_with_size",
480-
ids="name",
501+
ids="id",
481502
parents="parent",
482503
values="size",
483504
maxdepth=max_depth,
@@ -698,14 +719,18 @@ def symbols_from_nm(elf_file: str) -> list[Symbol]:
698719
return symbols
699720

700721

701-
def fetch_symbols(elf_file: str, fetch: FetchStyle) -> Tuple[list[Symbol], str]:
722+
def fetch_symbols(elf_file: str, fetch: FetchStyle, glob_filter: Optional[str]) -> Tuple[list[Symbol], str]:
702723
"""Returns the sumbol list and the separator used to split symbols
703724
"""
704725
match fetch:
705726
case FetchStyle.NM:
706-
return symbols_from_nm(elf_file), "::"
727+
symbols, separator = symbols_from_nm(elf_file), "::"
707728
case FetchStyle.OBJDUMP:
708-
return symbols_from_objdump(elf_file), '/'
729+
symbols, separator = symbols_from_objdump(elf_file), '/'
730+
if glob_filter is not None:
731+
symbols = [s for s in symbols if fnmatch.fnmatch(s.name, glob_filter)]
732+
733+
return symbols, separator
709734

710735

711736
def list_id(tree_path: list[str]) -> str:
@@ -813,6 +838,11 @@ def compute_symbol_diff(orig: list[Symbol], base: list[Symbol]) -> list[Symbol]:
813838
default=None,
814839
help="Zoom in the graph to ONLY the specified path as root (e.g. ::chip::app)",
815840
)
841+
@click.option(
842+
"--glob-filter",
843+
default=None,
844+
help="Glob filter by name",
845+
)
816846
@click.option(
817847
"--strip",
818848
default=None,
@@ -835,17 +865,21 @@ def main(
835865
zoom: Optional[str],
836866
strip: Optional[str],
837867
diff: Optional[str],
868+
glob_filter: Optional[str],
838869
):
839870
log_fmt = "%(asctime)s %(levelname)-7s %(message)s"
840871
coloredlogs.install(level=__LOG_LEVELS__[log_level], fmt=log_fmt)
841872

842-
symbols, separator = fetch_symbols(elf_file, __FETCH_STYLES__[fetch_via])
873+
symbols, separator = fetch_symbols(elf_file, __FETCH_STYLES__[fetch_via], glob_filter)
843874
title = elf_file
844875

876+
if glob_filter:
877+
title += f" FILTER {glob_filter}"
878+
845879
if diff:
846-
diff_symbols, _ = fetch_symbols(diff, __FETCH_STYLES__[fetch_via])
880+
diff_symbols, _ = fetch_symbols(diff, __FETCH_STYLES__[fetch_via], glob_filter)
847881
symbols = compute_symbol_diff(symbols, diff_symbols)
848-
title = f"{elf_file} COMPARED TO {diff}"
882+
title += f" COMPARED TO {diff}"
849883

850884
build_treemap(
851885
title, symbols, separator, __CHART_STYLES__[display_type], __COLOR_SCALES__[color], max_depth, zoom, strip

0 commit comments

Comments
 (0)