diff --git a/src/faebryk/core/cpp/__init__.pyi b/src/faebryk/core/cpp/__init__.pyi index 4f7814f2..08efaa91 100644 --- a/src/faebryk/core/cpp/__init__.pyi +++ b/src/faebryk/core/cpp/__init__.pyi @@ -181,4 +181,5 @@ def find_paths( src: Node, dst: Sequence[Node] ) -> tuple[list[list[GraphInterface]], list[Counter]]: ... def print_obj(obj: object) -> None: ... +def set_indiv_measure(value: bool) -> None: ... def set_leak_warnings(value: bool) -> None: ... diff --git a/src/faebryk/core/cpp/include/pathfinder/pathcounter.hpp b/src/faebryk/core/cpp/include/pathfinder/pathcounter.hpp index b8674135..72d8c864 100644 --- a/src/faebryk/core/cpp/include/pathfinder/pathcounter.hpp +++ b/src/faebryk/core/cpp/include/pathfinder/pathcounter.hpp @@ -9,6 +9,10 @@ inline bool INDIV_MEASURE = true; +inline void set_indiv_measure(bool v) { + INDIV_MEASURE = v; +} + class PathFinder; class BFSPath; diff --git a/src/faebryk/core/cpp/src/main.cpp b/src/faebryk/core/cpp/src/main.cpp index bc1e73c6..f07b51a7 100644 --- a/src/faebryk/core/cpp/src/main.cpp +++ b/src/faebryk/core/cpp/src/main.cpp @@ -68,6 +68,7 @@ PYMOD(m) { // TODO why this rv_pol needed m.def("find_paths", &find_paths, "src"_a, "dst"_a, nb::rv_policy::reference); + m.def("set_indiv_measure", &set_indiv_measure, "value"_a); // Graph using GI = GraphInterface; diff --git a/src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp b/src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp index 47dac73b..dc225b0e 100644 --- a/src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp +++ b/src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp @@ -313,11 +313,11 @@ bool PathFinder::_filter_conditional_link(BFSPath &p) { return true; } - if (link_conditional->needs_to_check_only_first_in_path()) { - if (p.size() > 1) { - return true; - } - } + // if (link_conditional->needs_to_check_only_first_in_path()) { + // if (p.size() > 1) { + // return true; + // } + // } // TODO check recoverable? return link_conditional->run_filter(edge->from, edge->to) == diff --git a/src/faebryk/core/moduleinterface.py b/src/faebryk/core/moduleinterface.py index 51c778d0..a1ec2a59 100644 --- a/src/faebryk/core/moduleinterface.py +++ b/src/faebryk/core/moduleinterface.py @@ -10,7 +10,6 @@ from faebryk.core.cpp import ( GraphInterfaceModuleConnection, - find_paths, ) from faebryk.core.graphinterface import GraphInterface from faebryk.core.link import ( @@ -19,14 +18,13 @@ LinkDirectConditionalFilterResult, ) from faebryk.core.node import CNode, Node, NodeException +from faebryk.core.pathfinder import Path, find_paths from faebryk.core.trait import Trait from faebryk.library.can_specialize import can_specialize from faebryk.libs.util import cast_assert, once logger = logging.getLogger(__name__) -type Path = list[GraphInterface] - class ModuleInterface(Node): class TraitT(Trait): ... @@ -103,12 +101,12 @@ def connect_shallow(self, *other: Self) -> Self: return self.connect(*other, linkcls=type(self).LinkDirectShallow()) def get_connected(self) -> dict[Self, Path]: - paths = find_paths(self, [])[0] + paths = find_paths(self, []) return {cast_assert(type(self), p[-1].node): p for p in paths} def is_connected_to(self, other: "ModuleInterface") -> list[Path]: return [ - path for path in find_paths(self, [other])[0] if path[-1] is other.self_gif + path for path in find_paths(self, [other]) if path[-1] is other.self_gif ] def specialize[T: ModuleInterface](self, special: T) -> T: diff --git a/src/faebryk/core/pathfinder.py b/src/faebryk/core/pathfinder.py new file mode 100644 index 00000000..fed3faed --- /dev/null +++ b/src/faebryk/core/pathfinder.py @@ -0,0 +1,115 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import io +from typing import Sequence + +from more_itertools import partition +from rich.console import Console +from rich.table import Table + +from faebryk.core.cpp import Counter, set_indiv_measure +from faebryk.core.cpp import find_paths as find_paths_cpp +from faebryk.core.graphinterface import GraphInterface +from faebryk.core.node import Node +from faebryk.libs.util import ConfigFlag + +type Path = list[GraphInterface] + + +# Also in C++ +INDIV_MEASURE = ConfigFlag( + "INDIV_MEASURE", default=True, descr="Measure individual paths" +) +set_indiv_measure(bool(INDIV_MEASURE)) + + +def find_paths(src: Node, dst: Sequence[Node]) -> list[Path]: + paths, counters = find_paths_cpp(src, dst) + + print(Counters(counters)) + return paths + + +class Counters: + def __init__(self, counters: list[Counter]): + self.counters: dict[str, Counter] = {c.name: c for c in counters} + + def __repr__(self): + table = Table(title="Filter Counters") + table.add_column("func", style="cyan", width=20) + table.add_column("in", style="green", justify="right") + table.add_column("weak in", style="green", justify="right") + table.add_column("out", style="green", justify="right") + # table.add_column("drop", style="cyan", justify="center") + table.add_column("filt", style="magenta", justify="right") + table.add_column("weaker", style="green", justify="right") + table.add_column("stronger", style="green", justify="right") + table.add_column("time", style="yellow", justify="right") + table.add_column("time/in", style="yellow", justify="right") + + individual, total = partition( + lambda x: x[1].total_counter, self.counters.items() + ) + individual = list(individual) + for section in partition(lambda x: x[1].multi, individual): + for k, v in sorted( + section, + key=lambda x: (x[1].out_cnt, x[1].in_cnt), + reverse=True, + ): + k_clean = ( + k.split("path_")[-1] + .replace("_", " ") + .removeprefix("by ") + .removeprefix("with ") + ) + if v.in_cnt == 0: + continue + table.add_row( + k_clean, + str(v.in_cnt), + str(v.weak_in_cnt), + str(v.out_cnt), + # "x" if getattr(k, "discovery_filter", False) else "", + f"{(1-v.out_cnt/v.in_cnt)*100:.1f} %" if v.in_cnt else "-", + str(v.out_weaker), + str(v.out_stronger), + f"{v.time_spent_s*1000:.2f} ms", + f"{v.time_spent_s/v.in_cnt*1000*1000:.2f} us" if v.in_cnt else "-", + ) + table.add_section() + + table.add_section() + for k, v in total: + if v.in_cnt == 0: + continue + table.add_row( + k, + str(v.in_cnt), + str(v.weak_in_cnt), + str(v.out_cnt), + # "x" if getattr(k, "discovery_filter", False) else "", + f"{(1-v.out_cnt/v.in_cnt)*100:.1f} %" if v.in_cnt else "-", + str(v.out_weaker), + str(v.out_stronger), + f"{v.time_spent_s*1000:.2f} ms", + f"{v.time_spent_s/v.in_cnt*1000*1000:.2f} us" if v.in_cnt else "-", + ) + if INDIV_MEASURE: + table.add_row( + "Total", + "", + "", + "", + # "", + "", + "", + "", + f"{sum(v.time_spent_s for _,v in individual)*1000:.2f} ms", + f"{sum(v.time_spent_s/v.in_cnt for _,v in individual if v.in_cnt)*1000*1000:.2f} us", # noqa: E501 + ) + + console = Console(record=True, width=120, file=io.StringIO()) + console.print(table) + return console.export_text(styles=True)