Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
H
Hercules
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
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
llvm
Hercules
Merge requests
!16
Refactor dot visualization
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Refactor dot visualization
dot_lib
into
main
Overview
0
Commits
3
Pipelines
0
Changes
3
Merged
rarbore2
requested to merge
dot_lib
into
main
1 year ago
Overview
0
Commits
3
Pipelines
0
Changes
3
Expand
Move dot to hercules_ir
Library utility for invoking xdot on IR graph
Xdot pass for invoking aforementioned utility between passes (without necessity of being verified)
Future TODO: hercules_opt
0
0
Merge request reports
Viewing commit
37e48e7f
Prev
Next
Show latest version
3 files
+
115
−
75
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
3
Search (e.g. *.vue) (Ctrl+P)
37e48e7f
Refactor hercules_dot
· 37e48e7f
Russel Arbore
authored
1 year ago
hercules_tools/hercules_dot/src/dot.rs
+
97
−
45
Options
extern
crate
hercules_ir
;
extern
crate
rand
;
use
std
::
collections
::
HashMap
;
use
std
::
env
::
temp_dir
;
use
std
::
fmt
::
Write
;
use
std
::
fs
::
File
;
use
std
::
io
::
Write
as
_
;
use
std
::
process
::
Command
;
use
rand
::
Rng
;
use
self
::
hercules_ir
::
*
;
/*
* Top level function to write a module out as a dot graph. Takes references to
* many analysis results to generate a more informative dot graph.
* Top level function to compute a dot graph for a module, and immediately
* render it using xdot.
*/
pub
fn
xdot_module
(
module
:
&
ir
::
Module
,
reverse_postorders
:
&
Vec
<
Vec
<
NodeID
>>
,
doms
:
Option
<&
Vec
<
DomTree
>>
,
fork_join_maps
:
Option
<&
Vec
<
HashMap
<
NodeID
,
NodeID
>>>
,
plans
:
Option
<&
Vec
<
Plan
>>
,
)
{
let
mut
tmp_path
=
temp_dir
();
let
mut
rng
=
rand
::
thread_rng
();
let
num
:
u64
=
rng
.gen
();
tmp_path
.push
(
format!
(
"hercules_dot_{}.dot"
,
num
));
let
mut
file
=
File
::
create
(
tmp_path
.clone
())
.expect
(
"PANIC: Unable to open output file."
);
let
mut
contents
=
String
::
new
();
write_dot
(
&
module
,
&
reverse_postorders
,
doms
,
fork_join_maps
,
plans
,
&
mut
contents
,
)
.expect
(
"PANIC: Unable to generate output file contents."
);
file
.write_all
(
contents
.as_bytes
())
.expect
(
"PANIC: Unable to write output file contents."
);
Command
::
new
(
"xdot"
)
.args
([
tmp_path
])
.output
()
.expect
(
"PANIC: Couldn't execute xdot."
);
}
/*
* Top level function to write a module out as a dot graph. Optionally takes
* references to many analysis results to generate a more informative dot graph.
*/
pub
fn
write_dot
<
W
:
Write
>
(
module
:
&
ir
::
Module
,
reverse_postorders
:
&
Vec
<
Vec
<
NodeID
>>
,
typing
:
&
ModuleTyping
,
doms
:
&
Vec
<
DomTree
>
,
fork_join_maps
:
&
Vec
<
HashMap
<
NodeID
,
NodeID
>>
,
plans
:
&
Vec
<
Plan
>
,
doms
:
Option
<&
Vec
<
DomTree
>>
,
fork_join_maps
:
Option
<&
Vec
<
HashMap
<
NodeID
,
NodeID
>>>
,
plans
:
Option
<&
Vec
<
Plan
>>
,
w
:
&
mut
W
,
)
->
std
::
fmt
::
Result
{
write_digraph_header
(
w
)
?
;
@@ -23,28 +63,38 @@ pub fn write_dot<W: Write>(
for
function_id
in
(
0
..
module
.functions
.len
())
.map
(
FunctionID
::
new
)
{
let
function
=
&
module
.functions
[
function_id
.idx
()];
let
reverse_postorder
=
&
reverse_postorders
[
function_id
.idx
()];
let
plan
=
&
plans
[
function_id
.idx
()];
let
plan
=
plans
.map
(|
plans
|
&
plans
[
function_id
.idx
()]
)
;
let
mut
reverse_postorder_node_numbers
=
vec!
[
0
;
function
.nodes
.len
()];
for
(
idx
,
id
)
in
reverse_postorder
.iter
()
.enumerate
()
{
reverse_postorder_node_numbers
[
id
.idx
()]
=
idx
;
}
write_subgraph_header
(
function_id
,
module
,
w
)
?
;
let
partition_to_node_map
=
plan
.invert_partition_map
();
let
mut
partition_to_node_map
=
plan
.map
(|
plan
|
plan
.invert_partition_map
()
)
;
// Step 1: draw IR graph itself. This includes all IR nodes and all edges
// between IR nodes.
for
partition_idx
in
0
..
plan
.num_partitions
{
let
partition_color
=
match
plan
.partition_devices
[
partition_idx
]
{
for
partition_idx
in
0
..
plan
.map_or
(
1
,
|
plan
|
plan
.num_partitions
)
{
let
partition_color
=
plan
.map
(|
plan
|
match
plan
.partition_devices
[
partition_idx
]
{
Device
::
CPU
=>
"lightblue"
,
Device
::
GPU
=>
"darkseagreen"
,
});
if
let
Some
(
partition_color
)
=
partition_color
{
write_partition_header
(
function_id
,
partition_idx
,
module
,
partition_color
,
w
)
?
;
}
let
nodes_ids
=
if
let
Some
(
partition_to_node_map
)
=
&
mut
partition_to_node_map
{
let
mut
empty
=
vec!
[];
std
::
mem
::
swap
(
&
mut
partition_to_node_map
[
partition_idx
],
&
mut
empty
);
empty
}
else
{
(
0
..
function
.nodes
.len
())
.map
(
NodeID
::
new
)
.collect
::
<
Vec
<
_
>>
()
};
write_partition_header
(
function_id
,
partition_idx
,
module
,
partition_color
,
w
)
?
;
for
node_id
in
&
partition_to_node_map
[
partition_idx
]
{
for
node_id
in
nodes_ids
.iter
()
{
let
node
=
&
function
.nodes
[
node_id
.idx
()];
let
dst_ty
=
&
module
.types
[
typing
[
function_id
.idx
()][
node_id
.idx
()]
.idx
()];
let
dst_strictly_control
=
node
.is_strictly_control
();
let
dst_control
=
dst_ty
.is_control
()
||
dst_strictly_control
;
let
dst_control
=
node
.is_control
();
// Control nodes are dark red, data nodes are dark blue.
let
color
=
if
dst_control
{
"darkred"
}
else
{
"darkblue"
};
@@ -54,14 +104,12 @@ pub fn write_dot<W: Write>(
function_id
,
color
,
module
,
&
plan
.schedules
[
node_id
.idx
()],
plan
.map_or
(
&
vec!
[],
|
plan
|
&
plan
.schedules
[
node_id
.idx
()]
)
,
w
,
)
?
;
for
u
in
def_use
::
get_uses
(
&
node
)
.as_ref
()
{
let
src_ty
=
&
module
.types
[
typing
[
function_id
.idx
()][
u
.idx
()]
.idx
()];
let
src_strictly_control
=
function
.nodes
[
u
.idx
()]
.is_strictly_control
();
let
src_control
=
src_ty
.is_control
()
||
src_strictly_control
;
let
src_control
=
function
.nodes
[
u
.idx
()]
.is_control
();
// An edge between control nodes is dashed. An edge between data
// nodes is filled. An edge between a control node and a data
@@ -106,35 +154,39 @@ pub fn write_dot<W: Write>(
// Step 2: draw dominance edges in dark green. Don't draw post dominance
// edges because then xdot lays out the graph strangely.
let
dom
=
&
doms
[
function_id
.idx
()];
for
(
child_id
,
(
_
,
parent_id
))
in
dom
.get_underlying_map
()
{
write_edge
(
*
child_id
,
function_id
,
*
parent_id
,
function_id
,
true
,
"darkgreen"
,
"dotted"
,
&
module
,
w
,
)
?
;
if
let
Some
(
doms
)
=
doms
{
let
dom
=
&
doms
[
function_id
.idx
()];
for
(
child_id
,
(
_
,
parent_id
))
in
dom
.get_underlying_map
()
{
write_edge
(
*
child_id
,
function_id
,
*
parent_id
,
function_id
,
true
,
"darkgreen"
,
"dotted"
,
&
module
,
w
,
)
?
;
}
}
// Step 3: draw fork join edges in dark magenta.
let
fork_join_map
=
&
fork_join_maps
[
function_id
.idx
()];
for
(
fork_id
,
join_id
)
in
fork_join_map
{
write_edge
(
*
join_id
,
function_id
,
*
fork_id
,
function_id
,
true
,
"darkmagenta"
,
"dotted"
,
&
module
,
w
,
)
?
;
if
let
Some
(
fork_join_maps
)
=
fork_join_maps
{
let
fork_join_map
=
&
fork_join_maps
[
function_id
.idx
()];
for
(
fork_id
,
join_id
)
in
fork_join_map
{
write_edge
(
*
join_id
,
function_id
,
*
fork_id
,
function_id
,
true
,
"darkmagenta"
,
"dotted"
,
&
module
,
w
,
)
?
;
}
}
write_graph_footer
(
w
)
?
;
Loading