Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
Spack
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
eic_tools
Spack
Commits
5d033fbd
Commit
5d033fbd
authored
10 years ago
by
Todd Gamblin
Browse files
Options
Downloads
Patches
Plain Diff
Expansion works properly, simplified graph code.
parent
b4b8339d
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
lib/spack/spack/cmd/graph.py
+2
-2
2 additions, 2 deletions
lib/spack/spack/cmd/graph.py
lib/spack/spack/graph.py
+146
-88
146 additions, 88 deletions
lib/spack/spack/graph.py
with
148 additions
and
90 deletions
lib/spack/spack/cmd/graph.py
+
2
−
2
View file @
5d033fbd
...
@@ -55,7 +55,7 @@ def graph(parser, args):
...
@@ -55,7 +55,7 @@ def graph(parser, args):
graph_dot
(
*
specs
)
graph_dot
(
*
specs
)
elif
specs
:
# ascii is default: user doesn't need to provide it explicitly
elif
specs
:
# ascii is default: user doesn't need to provide it explicitly
graph_ascii
(
specs
[
0
])
graph_ascii
(
specs
[
0
]
,
debug
=
spack
.
debug
)
for
spec
in
specs
[
1
:]:
for
spec
in
specs
[
1
:]:
print
# extra line bt/w independent graphs
print
# extra line bt/w independent graphs
graph_ascii
(
spec
)
graph_ascii
(
spec
,
debug
=
spack
.
debug
)
This diff is collapsed.
Click to expand it.
lib/spack/spack/graph.py
+
146
−
88
View file @
5d033fbd
...
@@ -29,7 +29,30 @@
...
@@ -29,7 +29,30 @@
about:
about:
graph_ascii() will output a colored graph of a spec in ascii format,
graph_ascii() will output a colored graph of a spec in ascii format,
knd of like the graph git shows with
"
git log --graph
"
.
kind of like the graph git shows with
"
git log --graph
"
, e.g.::
o mpileaks
|
\
| |
\
| o | callpath
|/| |
| |\|
| |\
\
| | |\
\
| | | | o adept-utils
| |_|_|/|
|/| | | |
o | | | | mpi
/ / / /
| | o | dyninst
| |/| |
|/|/| |
| | |/
| o | libdwarf
|/ /
o | libelf
/
o boost
graph_dot() will output a graph of a spec (or multiple specs) in dot
graph_dot() will output a graph of a spec (or multiple specs) in dot
format.
format.
...
@@ -102,11 +125,16 @@ def find(seq, predicate):
...
@@ -102,11 +125,16 @@ def find(seq, predicate):
return
-
1
return
-
1
# Names of different graph line states. We Record previous line
# states so that we can easily determine what to do when connecting.
states
=
(
'
node
'
,
'
collapse
'
,
'
merge-right
'
,
'
expand-right
'
,
'
back-edge
'
)
NODE
,
COLLAPSE
,
MERGE_RIGHT
,
EXPAND_RIGHT
,
BACK_EDGE
=
states
class
AsciiGraph
(
object
):
class
AsciiGraph
(
object
):
def
__init__
(
self
):
def
__init__
(
self
):
# These can be set after initialization or after a call to
# These can be set after initialization or after a call to
# graph() to change behavior.
# graph() to change behavior.
self
.
node_character
=
'
o
'
self
.
node_character
=
'
*
'
self
.
debug
=
False
self
.
debug
=
False
self
.
indent
=
0
self
.
indent
=
0
...
@@ -120,6 +148,7 @@ def __init__(self):
...
@@ -120,6 +148,7 @@ def __init__(self):
self
.
_out
=
None
# Output stream
self
.
_out
=
None
# Output stream
self
.
_frontier
=
None
# frontier
self
.
_frontier
=
None
# frontier
self
.
_nodes
=
None
# dict from name -> node
self
.
_nodes
=
None
# dict from name -> node
self
.
_prev_state
=
None
# State of previous line
def
_indent
(
self
):
def
_indent
(
self
):
...
@@ -133,7 +162,7 @@ def _write_edge(self, string, index, sub=0):
...
@@ -133,7 +162,7 @@ def _write_edge(self, string, index, sub=0):
self
.
_out
.
write
(
edge
)
self
.
_out
.
write
(
edge
)
def
_connect_deps
(
self
,
i
,
deps
,
collapse
,
label
):
def
_connect_deps
(
self
,
i
,
deps
,
label
=
None
):
"""
Connect dependencies to existing edges in the frontier.
"""
Connect dependencies to existing edges in the frontier.
``deps`` are to be inserted at position i in the
``deps`` are to be inserted at position i in the
...
@@ -147,9 +176,6 @@ def _connect_deps(self, i, deps, collapse, label):
...
@@ -147,9 +176,6 @@ def _connect_deps(self, i, deps, collapse, label):
Parameters:
Parameters:
collapse -- whether the frontier is collapsing or staying the
same size.
label -- optional debug label for the connection.
label -- optional debug label for the connection.
Returns: True if the deps were connected to another edge
Returns: True if the deps were connected to another edge
...
@@ -161,20 +187,25 @@ def _connect_deps(self, i, deps, collapse, label):
...
@@ -161,20 +187,25 @@ def _connect_deps(self, i, deps, collapse, label):
if
len
(
deps
)
==
1
and
deps
in
self
.
_frontier
:
if
len
(
deps
)
==
1
and
deps
in
self
.
_frontier
:
j
=
self
.
_frontier
.
index
(
deps
)
j
=
self
.
_frontier
.
index
(
deps
)
# connect to the left
# convert a right connection into a left connection
if
j
<
i
:
if
i
<
j
:
if
i
-
j
>
1
:
# two lines if distance > 1
self
.
_frontier
.
pop
(
j
)
self
.
_back_edge
([],
j
,
i
,
True
,
label
)
self
.
_frontier
.
insert
(
i
,
deps
)
self
.
_back_edge
([
j
],
-
1
,
-
1
,
(
i
-
j
==
1
),
label
)
return
self
.
_connect_deps
(
j
,
deps
,
label
)
# connect to the right
collapse
=
True
else
:
if
self
.
_prev_state
==
EXPAND_RIGHT
:
if
i
<
j
:
# Special case for when prev. line expanded (spacing is off by 1)
self
.
_frontier
.
pop
(
j
)
# Need two lines here even when distance in frontier is 1.
self
.
_frontier
.
insert
(
i
,
deps
)
self
.
_back_edge_line
([],
j
,
i
+
1
,
True
,
label
+
"
-1.5
"
+
str
((
i
,
j
)))
if
j
-
i
>
1
:
collapse
=
False
self
.
_back_edge
([],
i
,
j
+
1
,
collapse
,
label
)
self
.
_back_edge
([
i
],
-
1
,
-
1
,
not
(
j
-
i
>
1
)
and
collapse
,
label
)
elif
i
-
j
>
1
:
# We need two lines to connect if distance > 1
self
.
_back_edge_line
([],
j
,
i
,
True
,
label
+
"
-1
"
+
str
((
i
,
j
)))
collapse
=
False
self
.
_back_edge_line
([
j
],
-
1
,
-
1
,
collapse
,
label
+
"
-2
"
+
str
((
i
,
j
)))
return
True
return
True
elif
deps
:
elif
deps
:
...
@@ -182,22 +213,20 @@ def _connect_deps(self, i, deps, collapse, label):
...
@@ -182,22 +213,20 @@ def _connect_deps(self, i, deps, collapse, label):
return
False
return
False
def
_add_deps_to_frontier
(
self
,
node
,
i
):
def
_set_state
(
self
,
state
,
label
=
None
):
"""
Add dependencies to frontier.
if
state
not
in
states
:
raise
ValueError
(
"
Invalid graph state!
"
)
Adds the dependencies of <node> to the frontier, and connects
self
.
_prev_state
=
state
them to other open edges if they match. Also deletes parent
pointers in the node to mark edges as covered.
"""
deps
=
sorted
((
d
for
d
in
node
.
dependencies
),
reverse
=
True
)
self
.
_connect_deps
(
i
,
deps
,
True
,
"
add_deps
"
)
for
d
in
deps
:
del
self
.
_nodes
[
d
].
dependents
[
node
.
name
]
if
self
.
debug
:
self
.
_out
.
write
(
"
"
*
20
)
self
.
_out
.
write
(
"
%-20s
"
%
(
str
(
self
.
_prev_state
)
if
self
.
_prev_state
else
''
))
self
.
_out
.
write
(
"
%-20s
"
%
(
str
(
label
)
if
label
else
''
))
self
.
_out
.
write
(
"
%s
"
%
self
.
_frontier
)
def
_back_edge
(
self
,
prev_ends
,
end
,
start
,
collapse
,
label
=
None
):
def
_back_edge
_line
(
self
,
prev_ends
,
end
,
start
,
collapse
,
label
=
None
):
"""
Write part of a backwards edge in the graph.
"""
Write part of a backwards edge in the graph.
Writes single- or multi-line backward edges in an ascii graph.
Writes single- or multi-line backward edges in an ascii graph.
...
@@ -267,12 +296,64 @@ def advance(to_pos, edges):
...
@@ -267,12 +296,64 @@ def advance(to_pos, edges):
else
:
else
:
advance
(
flen
,
lambda
:
[(
"
|
"
,
self
.
_pos
)]
)
advance
(
flen
,
lambda
:
[(
"
|
"
,
self
.
_pos
)]
)
if
self
.
debug
:
self
.
_set_state
(
BACK_EDGE
,
label
)
self
.
_out
.
write
(
"
"
*
10
)
self
.
_out
.
write
(
"
\n
"
)
if
label
:
self
.
_out
.
write
(
label
)
self
.
_out
.
write
(
"
%s
"
%
self
.
_frontier
)
def
_node_line
(
self
,
index
,
name
):
"""
Writes a line with a node at index.
"""
self
.
_indent
()
for
c
in
range
(
index
):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_out
.
write
(
"
%s
"
%
self
.
node_character
)
for
c
in
range
(
index
+
1
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_out
.
write
(
"
%s
"
%
name
)
self
.
_set_state
(
NODE
)
self
.
_out
.
write
(
"
\n
"
)
def
_collapse_line
(
self
,
index
):
"""
Write a collapsing line after a node was added at index.
"""
self
.
_indent
()
for
c
in
range
(
index
):
self
.
_write_edge
(
"
|
"
,
c
)
for
c
in
range
(
index
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
/
"
,
c
)
self
.
_set_state
(
COLLAPSE
)
self
.
_out
.
write
(
"
\n
"
)
def
_merge_right_line
(
self
,
index
):
"""
Edge at index is same as edge to right. Merge directly with
'
\'
"""
self
.
_indent
()
for
c
in
range
(
index
):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_write_edge
(
"
|
"
,
index
)
self
.
_write_edge
(
"
\\
"
,
index
+
1
)
for
c
in
range
(
index
+
1
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_set_state
(
MERGE_RIGHT
)
self
.
_out
.
write
(
"
\n
"
)
def
_expand_right_line
(
self
,
index
):
self
.
_indent
()
for
c
in
range
(
index
):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_write_edge
(
"
|
"
,
index
)
self
.
_write_edge
(
"
\\
"
,
index
+
1
)
for
c
in
range
(
index
+
2
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
\\
"
,
c
)
self
.
_set_state
(
EXPAND_RIGHT
)
self
.
_out
.
write
(
"
\n
"
)
self
.
_out
.
write
(
"
\n
"
)
...
@@ -311,27 +392,22 @@ def write(self, spec, **kwargs):
...
@@ -311,27 +392,22 @@ def write(self, spec, **kwargs):
self
.
_name_to_color
=
dict
((
name
,
self
.
colors
[
i
%
len
(
self
.
colors
)])
self
.
_name_to_color
=
dict
((
name
,
self
.
colors
[
i
%
len
(
self
.
colors
)])
for
i
,
name
in
enumerate
(
topo_order
))
for
i
,
name
in
enumerate
(
topo_order
))
# This array tracks the open edges at the frontier of the
# Frontier tracks open edges of the graph as it's written out.
# graph we're writing out.
self
.
_frontier
=
[[
spec
.
name
]]
self
.
_frontier
=
[]
self
.
_add_deps_to_frontier
(
spec
,
0
)
self
.
_indent
()
self
.
_out
.
write
(
'
%s %s
\n
'
%
(
self
.
node_character
,
spec
.
name
))
topo_order
.
pop
()
while
self
.
_frontier
:
while
self
.
_frontier
:
# Find an unexpanded part of frontier
# Find an unexpanded part of frontier
i
=
find
(
self
.
_frontier
,
lambda
f
:
len
(
f
)
>
1
)
i
=
find
(
self
.
_frontier
,
lambda
f
:
len
(
f
)
>
1
)
# Expand frontier until there are enough columns for all children.
if
i
>=
0
:
if
i
>=
0
:
# Expand frontier until there are enough columns for all children.
# Figure out how many back connections there are and
# Figure out how many back connections there are and
# sort them so we do them in order
# sort them so we do them in order
back
=
[]
back
=
[]
for
d
in
self
.
_frontier
[
i
]:
for
d
in
self
.
_frontier
[
i
]:
b
=
find
(
self
.
_frontier
[:
i
],
lambda
f
:
f
==
[
d
])
b
=
find
(
self
.
_frontier
[:
i
],
lambda
f
:
f
==
[
d
])
if
b
!=
-
1
:
back
.
append
((
b
,
d
))
if
b
!=
-
1
:
back
.
append
((
b
,
d
))
# Do all back connections in sorted order so we can
# Do all back connections in sorted order so we can
# pipeline them and save space.
# pipeline them and save space.
...
@@ -341,79 +417,61 @@ def write(self, spec, **kwargs):
...
@@ -341,79 +417,61 @@ def write(self, spec, **kwargs):
for
j
,
(
b
,
d
)
in
enumerate
(
back
):
for
j
,
(
b
,
d
)
in
enumerate
(
back
):
self
.
_frontier
[
i
].
remove
(
d
)
self
.
_frontier
[
i
].
remove
(
d
)
if
i
-
b
>
1
:
if
i
-
b
>
1
:
self
.
_back_edge
(
prev_ends
,
b
,
i
,
False
)
self
.
_back_edge
_line
(
prev_ends
,
b
,
i
,
False
,
'
left-1
'
)
del
prev_ends
[:]
del
prev_ends
[:]
prev_ends
.
append
(
b
)
prev_ends
.
append
(
b
)
self
.
_back_edge
(
prev_ends
,
-
1
,
-
1
,
False
)
self
.
_back_edge
_line
(
prev_ends
,
-
1
,
-
1
,
False
,
'
left-2
'
)
if
not
self
.
_frontier
[
i
]:
if
not
self
.
_frontier
[
i
]:
self
.
_frontier
.
pop
(
i
)
self
.
_frontier
.
pop
(
i
)
elif
len
(
self
.
_frontier
[
i
])
>
1
:
elif
len
(
self
.
_frontier
[
i
])
>
1
:
# Expand forawrd after doing all back connections
# Expand forward after doing all back connections
self
.
_indent
()
for
c
in
range
(
i
):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_write_edge
(
"
|
"
,
i
)
if
(
i
+
1
<
len
(
self
.
_frontier
)
and
len
(
self
.
_frontier
[
i
+
1
])
==
1
if
(
i
+
1
<
len
(
self
.
_frontier
)
and
len
(
self
.
_frontier
[
i
+
1
])
==
1
and
self
.
_frontier
[
i
+
1
][
0
]
in
self
.
_frontier
[
i
]):
and
self
.
_frontier
[
i
+
1
][
0
]
in
self
.
_frontier
[
i
]):
# We need to connect to the element to the right.
# We need to connect to the element to the right.
# Keep lines straight by connecting directly and
# Keep lines straight by connecting directly and
# avoiding
immediate
expand/contract.
# avoiding
unnecessary
expand/contract.
name
=
self
.
_frontier
[
i
+
1
][
0
]
name
=
self
.
_frontier
[
i
+
1
][
0
]
self
.
_frontier
[
i
].
remove
(
name
)
self
.
_frontier
[
i
].
remove
(
name
)
self
.
_merge_right_line
(
i
)
self
.
_write_edge
(
"
\\
"
,
i
+
1
)
for
c
in
range
(
i
+
1
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_out
.
write
(
"
\n
"
)
else
:
else
:
# Just allow the expansion here.
# Just allow the expansion here.
name
=
self
.
_frontier
[
i
].
pop
(
0
)
name
=
self
.
_frontier
[
i
].
pop
(
0
)
deps
=
[
name
]
deps
=
[
name
]
self
.
_write_edge
(
"
\\
"
,
i
)
self
.
_frontier
.
insert
(
i
,
deps
)
for
c
in
range
(
i
+
1
,
len
(
self
.
_frontier
)):
self
.
_expand_right_line
(
i
)
self
.
_write_edge
(
"
\\
"
,
c
)
self
.
_out
.
write
(
"
\n
"
)
self
.
_frontier
.
pop
(
i
)
self
.
_connect_deps
(
i
,
deps
,
True
,
"
expansion
"
)
self
.
_connect_deps
(
i
,
deps
,
"
post-expand
"
)
# Handle any remaining back edges to the right
# Handle any remaining back edges to the right
j
=
i
+
1
j
=
i
+
1
while
j
<
len
(
self
.
_frontier
):
while
j
<
len
(
self
.
_frontier
):
deps
=
self
.
_frontier
.
pop
(
j
)
deps
=
self
.
_frontier
.
pop
(
j
)
if
not
self
.
_connect_deps
(
j
,
deps
,
True
,
"
rem_back
"
):
if
not
self
.
_connect_deps
(
j
,
deps
,
"
back-from-right
"
):
j
+=
1
j
+=
1
else
:
else
:
# Nothing to expand; add dependencies for a node.
name
=
topo_order
.
pop
()
name
=
topo_order
.
pop
()
node
=
self
.
_nodes
[
name
]
node
=
self
.
_nodes
[
name
]
# Find the next node in topo order and remove it from
# Find the named node in the frontier and draw it.
# the frontier. Since specs are single-rooted DAGs,
# the node is always there. If the graph had multiple
# roots, we'd need to handle that case case of a new root.
i
=
find
(
self
.
_frontier
,
lambda
f
:
name
in
f
)
i
=
find
(
self
.
_frontier
,
lambda
f
:
name
in
f
)
self
.
_frontier
.
pop
(
i
)
self
.
_node_line
(
i
,
name
)
self
.
_indent
()
for
c
in
range
(
i
):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_out
.
write
(
"
%s
"
%
self
.
node_character
)
for
c
in
range
(
i
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
|
"
,
c
)
self
.
_out
.
write
(
"
%s
\n
"
%
name
)
# Replace node with its dependencies
self
.
_frontier
.
pop
(
i
)
if
node
.
dependencies
:
if
node
.
dependencies
:
self
.
_add_deps_to_frontier
(
node
,
i
)
deps
=
sorted
((
d
for
d
in
node
.
dependencies
),
reverse
=
True
)
self
.
_connect_deps
(
i
,
deps
,
"
new-deps
"
)
# anywhere.
elif
self
.
_frontier
:
elif
self
.
_frontier
:
self
.
_indent
()
self
.
_collapse_line
(
i
)
for
c
in
range
(
i
):
self
.
_write_edge
(
"
|
"
,
c
)
for
c
in
range
(
i
,
len
(
self
.
_frontier
)):
self
.
_write_edge
(
"
/
"
,
c
)
self
.
_out
.
write
(
"
\n
"
)
def
graph_ascii
(
spec
,
**
kwargs
):
def
graph_ascii
(
spec
,
**
kwargs
):
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment