diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-01 04:54:14 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-01 05:09:45 -0600 |
commit | ab02d73a5bf6369d567d408d0544748dfd0303ea (patch) | |
tree | 04170be556fc797da75f4896407478b63c98c77e | |
parent | 352da947a02ff7658deb7729efa8b2cf7ce7a5cc (diff) |
measurestack: Try to tidy analyze.py a bit
-rw-r--r-- | build-aux/measurestack/analyze.py | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/build-aux/measurestack/analyze.py b/build-aux/measurestack/analyze.py index a5ac6e5..d4ca721 100644 --- a/build-aux/measurestack/analyze.py +++ b/build-aux/measurestack/analyze.py @@ -21,6 +21,8 @@ __all__ = [ "analyze", ] +# types ######################################################################## + class BaseName: # class ########################################################## @@ -156,6 +158,8 @@ class Application(typing.Protocol): def skip_call(self, chain: typing.Sequence[QName], funcname: QName) -> bool: ... +# code ######################################################################### + re_node_label = re.compile( r"(?P<funcname>[^\n]+)\n" + r"(?P<location>[^\n]+:[0-9]+:[0-9]+)\n" @@ -166,13 +170,37 @@ re_node_label = re.compile( ) -def analyze( - *, +class _Graph: + graph: dict[QName, Node] + qualified: dict[BaseName, set[QName]] + + def resolve_funcname(self, funcname: QName) -> QName | None: + # Handle `ld --wrap` functions + if QName(f"__wrap_{str(funcname)}") in self.graph: + return QName(f"__wrap_{str(funcname)}") + if ( + str(funcname).startswith("__real_") + and QName(str(funcname)[len("__real_") :]) in self.graph + ): + funcname = QName(str(funcname)[len("__real_") :]) + + # Usual case + if funcname in self.graph: + return funcname + + # Handle `__weak` functions + if ":" not in str(funcname): + qnames = self.qualified.get(BaseName(str(funcname)), set()) + if len(qnames) == 1: + return next(name for name in qnames) + + return None + + +def _make_graph( ci_fnames: typing.Collection[str], - app_func_filters: dict[str, typing.Callable[[QName], tuple[int, bool]]], app: Application, - cfg_max_call_depth: int, -) -> AnalyzeResult: +) -> _Graph: graph: dict[QName, Node] = {} qualified: dict[BaseName, set[QName]] = {} @@ -249,34 +277,27 @@ def analyze( raise ValueError(f"duplicate node {node.funcname}") graph[node.funcname] = node + ret = _Graph() + ret.graph = graph + ret.qualified = qualified + return ret + + +def analyze( + *, + ci_fnames: typing.Collection[str], + app_func_filters: dict[str, typing.Callable[[QName], tuple[int, bool]]], + app: Application, + cfg_max_call_depth: int, +) -> AnalyzeResult: + graphdata = _make_graph(ci_fnames, app) + missing: set[QName] = set() dynamic: set[QName] = set() included_funcs: set[QName] = set() dbg = False - def resolve_funcname(funcname: QName) -> QName | None: - # Handle `ld --wrap` functions - if QName(f"__wrap_{str(funcname)}") in graph: - return QName(f"__wrap_{str(funcname)}") - if ( - str(funcname).startswith("__real_") - and QName(str(funcname)[len("__real_") :]) in graph - ): - funcname = QName(str(funcname)[len("__real_") :]) - - # Usual case - if funcname in graph: - return funcname - - # Handle `__weak` functions - if ":" not in str(funcname): - qnames = qualified.get(BaseName(str(funcname)), set()) - if len(qnames) == 1: - return next(name for name in qnames) - - return None - track_inclusion: bool = True def nstatic( @@ -286,7 +307,7 @@ def analyze( ) -> int: nonlocal dbg nonlocal track_inclusion - funcname = resolve_funcname(orig_funcname) + funcname = graphdata.resolve_funcname(orig_funcname) if not funcname: if chain and app.skip_call(chain, orig_funcname): if dbg: @@ -305,7 +326,7 @@ def analyze( if len(chain) == cfg_max_call_depth: raise ValueError(f"max call depth exceeded: {[*chain, funcname]}") - node = graph[funcname] + node = graphdata.graph[funcname] if dbg: print(f"//dbg: {'- '*len(chain)}{funcname}\t{node.nstatic}") if node.usage_kind == "dynamic" or node.ndynamic > 0: @@ -325,7 +346,7 @@ def analyze( groups: dict[str, AnalyzeResultGroup] = {} for grp_name, grp_filter in app_func_filters.items(): rows: dict[QName, AnalyzeResultVal] = {} - for funcname in graph: + for funcname in graphdata.graph: cnt, track_inclusion = grp_filter(funcname) if cnt: rows[funcname] = AnalyzeResultVal(nstatic=nstatic(funcname), cnt=cnt) |