Skip to content

Commit

Permalink
SERVER-56141 added in degree one libdeps analyzer and removed existen…
Browse files Browse the repository at this point in the history
…ce of shims from analyzer.
  • Loading branch information
dmoody256 authored and Evergreen Agent committed May 5, 2021
1 parent 5a36b11 commit 76eab0d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 48 deletions.
1 change: 0 additions & 1 deletion SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,6 @@ def shim_library(env, name, needs_link=False, *args, **kwargs):

for n in nodes:
setattr(n.attributes, "needs_link", needs_link)
setattr(n.attributes, "is_shim", True)

return nodes

Expand Down
3 changes: 3 additions & 0 deletions buildscripts/libdeps/SCHEMA_CHANGE_LOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
3 removed shim node property
2 flipped edge direction in graph file data
1 initial schema
38 changes: 19 additions & 19 deletions buildscripts/libdeps/analyzer_unittests.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
from libdeps.graph import LibdepsGraph, EdgeProps, NodeProps, CountTypes


def add_node(graph, node, builder, shim):
def add_node(graph, node, builder):
"""Add a node to the graph."""

graph.add_nodes_from([(node, {NodeProps.bin_type.name: builder, NodeProps.shim.name: shim})])
graph.add_nodes_from([(node, {NodeProps.bin_type.name: builder})])


def add_edge(graph, from_node, to_node, **kwargs):
Expand Down Expand Up @@ -74,15 +74,15 @@ def get_double_diamond_mock_graph():
# \lib4.so \lib8.so
#

add_node(graph, 'lib1.so', 'SharedLibrary', False)
add_node(graph, 'lib2.so', 'SharedLibrary', False)
add_node(graph, 'lib3.so', 'SharedLibrary', False)
add_node(graph, 'lib4.so', 'SharedLibrary', False)
add_node(graph, 'lib5.so', 'SharedLibrary', False)
add_node(graph, 'lib6.so', 'SharedLibrary', False)
add_node(graph, 'lib7.so', 'SharedLibrary', False)
add_node(graph, 'lib8.so', 'SharedLibrary', False)
add_node(graph, 'lib9.so', 'SharedLibrary', False)
add_node(graph, 'lib1.so', 'SharedLibrary')
add_node(graph, 'lib2.so', 'SharedLibrary')
add_node(graph, 'lib3.so', 'SharedLibrary')
add_node(graph, 'lib4.so', 'SharedLibrary')
add_node(graph, 'lib5.so', 'SharedLibrary')
add_node(graph, 'lib6.so', 'SharedLibrary')
add_node(graph, 'lib7.so', 'SharedLibrary')
add_node(graph, 'lib8.so', 'SharedLibrary')
add_node(graph, 'lib9.so', 'SharedLibrary')

add_edge(graph, 'lib1.so', 'lib2.so', direct=True, visibility=graph.get_deptype('Public'))
add_edge(graph, 'lib2.so', 'lib3.so', direct=True, visibility=graph.get_deptype('Public'))
Expand Down Expand Up @@ -159,12 +159,12 @@ def get_basic_mock_graph():
# \-lib6.so

# nodes
add_node(graph, 'lib1.so', 'SharedLibrary', False)
add_node(graph, 'lib2.so', 'SharedLibrary', False)
add_node(graph, 'lib3.so', 'SharedLibrary', False)
add_node(graph, 'lib4.so', 'SharedLibrary', False)
add_node(graph, 'lib5.so', 'SharedLibrary', False)
add_node(graph, 'lib6.so', 'SharedLibrary', False)
add_node(graph, 'lib1.so', 'SharedLibrary')
add_node(graph, 'lib2.so', 'SharedLibrary')
add_node(graph, 'lib3.so', 'SharedLibrary')
add_node(graph, 'lib4.so', 'SharedLibrary')
add_node(graph, 'lib5.so', 'SharedLibrary')
add_node(graph, 'lib6.so', 'SharedLibrary')

# direct edges
add_edge(graph, 'lib1.so', 'lib2.so', direct=True, visibility=graph.get_deptype('Public'))
Expand Down Expand Up @@ -428,7 +428,7 @@ def test_counts_basic(self):

expected_result = {
"NODE": 6, "EDGE": 13, "DIR_EDGE": 7, "TRANS_EDGE": 6, "DIR_PUB_EDGE": 6,
"PUB_EDGE": 12, "PRIV_EDGE": 1, "IF_EDGE": 0, "SHIM": 0, "PROG": 0, "LIB": 6
"PUB_EDGE": 12, "PRIV_EDGE": 1, "IF_EDGE": 0, "PROG": 0, "LIB": 6
}
self.run_counts(expected_result, libdeps_graph)

Expand All @@ -439,7 +439,7 @@ def test_counts_double_diamond(self):

expected_result = {
"NODE": 9, "EDGE": 34, "DIR_EDGE": 10, "TRANS_EDGE": 24, "DIR_PUB_EDGE": 10,
"PUB_EDGE": 34, "PRIV_EDGE": 0, "IF_EDGE": 0, "SHIM": 0, "PROG": 0, "LIB": 9
"PUB_EDGE": 34, "PRIV_EDGE": 0, "IF_EDGE": 0, "PROG": 0, "LIB": 9
}
self.run_counts(expected_result, libdeps_graph)

Expand Down
9 changes: 8 additions & 1 deletion buildscripts/libdeps/gacli.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ def _get_help_string(self, action):
{help_text[CountTypes.PUB_EDGE.name]}count edges that are public
{help_text[CountTypes.PRIV_EDGE.name]}count edges that are private
{help_text[CountTypes.IF_EDGE.name]}count edges that are interface
{help_text[CountTypes.SHIM.name]}count shim nodes
{help_text[CountTypes.LIB.name]}count library nodes
{help_text[CountTypes.PROG.name]}count program nodes
""")
Expand Down Expand Up @@ -159,6 +158,11 @@ def setup_args_parser():
"[from_node] [to_node]: Print edges between two nodes, which if removed would break the dependency between those "
+ "nodes,.")

parser.add_argument(
'--indegree-one', action='store_true', default=False, help=
"Find candidate nodes for merging by searching the graph for nodes with only one node which depends on them."
)

args = parser.parse_args()

for arg_list in args.graph_paths:
Expand Down Expand Up @@ -212,6 +216,9 @@ def main():
analysis.append(
libdeps_analyzer.CriticalEdges(libdeps_graph, analyzer_args[0], analyzer_args[1]))

if args.indegree_one:
analysis.append(libdeps_analyzer.InDegreeOne(libdeps_graph))

analysis += libdeps_analyzer.linter_factory(libdeps_graph, args.lint)

if args.build_data:
Expand Down
63 changes: 40 additions & 23 deletions buildscripts/libdeps/libdeps/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,22 +328,6 @@ def run(self):
int(self.get_deptype('Interface')))


class ShimCounter(Counter):
"""Counts and reports number of shim nodes in the graph."""

def __init__(self, graph):
"""Store graph and set type."""

super().__init__(graph)
self._count_type = CountTypes.SHIM.name

@schema_check(schema_version=1)
def run(self):
"""Count the graphs shim nodes."""

return self.node_type_count(NodeProps.shim.name, True)


class LibCounter(Counter):
"""Counts and reports number of library nodes in the graph."""

Expand Down Expand Up @@ -388,7 +372,6 @@ def counter_factory(graph, counters, progressbar=True):
CountTypes.PUB_EDGE.name: PublicEdgeCounter,
CountTypes.PRIV_EDGE.name: PrivateEdgeCounter,
CountTypes.IF_EDGE.name: InterfaceEdgeCounter,
CountTypes.SHIM.name: ShimCounter,
CountTypes.LIB.name: LibCounter,
CountTypes.PROG.name: ProgCounter,
}
Expand Down Expand Up @@ -492,6 +475,37 @@ def report(self, report):
report[DependsReportTypes.EXCLUDE_DEPENDS.name][tuple(self._nodes)] = self.run()


class InDegreeOne(Analyzer):
"""
Finds library nodes which have 1 or 0 dependers.
Such libraries are good candidates for merging or deletion.
"""

@schema_check(schema_version=1)
def run(self):
"""Search the graph for in degree 1 or 0 nodes."""

in_degree_one_nodes = []
for node, data in self._dependency_graph.nodes(data=True):
if (len(self._dependents_graph[node]) < 2
and data[NodeProps.bin_type.name] == 'SharedLibrary'):

if len(self._dependents_graph[node]) == 1:
depender = list(self._dependents_graph[node].items())[0][0]
else:
depender = None

in_degree_one_nodes.append([node, depender])

return sorted(in_degree_one_nodes)

def report(self, report):
"""Add the indegree one list to the report."""

report[DependsReportTypes.IN_DEGREE_ONE.name] = self.run()


class GraphPaths(Analyzer):
"""Finds all paths between two nodes in the graph."""

Expand Down Expand Up @@ -631,11 +645,10 @@ def run(self):
for edge in self._dependents_graph.edges:
edge_attribs = self._dependents_graph[edge[0]][edge[1]]

if (edge_attribs.get(EdgeProps.direct.name) and edge_attribs.get(
EdgeProps.visibility.name) == int(self.get_deptype('Public'))
and not self._dependents_graph.nodes()[edge[0]].get(NodeProps.shim.name)
and self._dependents_graph.nodes()[edge[1]].get(
NodeProps.bin_type.name) == 'SharedLibrary'):
if (edge_attribs.get(EdgeProps.direct.name)
and edge_attribs.get(EdgeProps.visibility.name) == int(
self.get_deptype('Public')) and self._dependents_graph.nodes()[edge[1]].get(
NodeProps.bin_type.name) == 'SharedLibrary'):

# First we will get all the transitive libdeps the dependent node
# induces, while we are getting those we also check if the depender
Expand Down Expand Up @@ -760,7 +773,6 @@ class GaPrettyPrinter(GaPrinter):
CountTypes.PUB_EDGE.name: "Public Edges in Graph: {}",
CountTypes.PRIV_EDGE.name: "Private Edges in Graph: {}",
CountTypes.IF_EDGE.name: "Interface Edges in Graph: {}",
CountTypes.SHIM.name: "Shim Nodes in Graph: {}",
CountTypes.LIB.name: "Library Nodes in Graph: {}",
CountTypes.PROG.name: "Program Nodes in Graph: {}",
}
Expand Down Expand Up @@ -813,6 +825,11 @@ def _print_depends_reports(self, results):
f"=>critical edges between {nodes[0]} and {nodes[1]}:",
results[DependsReportTypes.CRITICAL_EDGES.name][nodes])

if DependsReportTypes.IN_DEGREE_ONE.name in results:
print("\nLibrary nodes with 1 or 0 dependers:")
for count, nodes in enumerate(results[DependsReportTypes.IN_DEGREE_ONE.name], start=1):
print(f" {count}: '{nodes[0]}' <- '{nodes[1]}'")

def print(self):
"""Print the result data."""
results = self._libdeps_graph_analysis.get_results()
Expand Down
3 changes: 1 addition & 2 deletions buildscripts/libdeps/libdeps/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class CountTypes(Enum):
PUB_EDGE = auto()
PRIV_EDGE = auto()
IF_EDGE = auto()
SHIM = auto()
PROG = auto()
LIB = auto()

Expand All @@ -67,6 +66,7 @@ class DependsReportTypes(Enum):
EXCLUDE_DEPENDS = auto()
GRAPH_PATHS = auto()
CRITICAL_EDGES = auto()
IN_DEGREE_ONE = auto()


class LinterTypes(Enum):
Expand All @@ -87,7 +87,6 @@ class EdgeProps(Enum):
class NodeProps(Enum):
"""Enums for node properties."""

shim = auto()
bin_type = auto()


Expand Down
3 changes: 1 addition & 2 deletions site_scons/libdeps_next.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,6 @@ def add_node_from(env, node):
str(node.abspath),
{
NodeProps.bin_type.name: node.builder.get_name(env),
NodeProps.shim.name: getattr(node.attributes, "is_shim", False)
})])

def add_edge_from(env, from_node, to_node, visibility, direct):
Expand Down Expand Up @@ -1438,7 +1437,7 @@ def append_symbol_deps(env, symbol_deps_file):

env['LIBDEPS_SYMBOL_DEP_FILES'] = symbol_deps
env['LIBDEPS_GRAPH_FILE'] = env.File("${BUILD_DIR}/libdeps/libdeps.graphml")
env['LIBDEPS_GRAPH_SCHEMA_VERSION'] = 2
env['LIBDEPS_GRAPH_SCHEMA_VERSION'] = 3
env["SYMBOLDEPSSUFFIX"] = '.symbol_deps'

libdeps_graph = LibdepsGraph()
Expand Down

0 comments on commit 76eab0d

Please sign in to comment.