Skip to content
Snippets Groups Projects

Refactor dot visualization

Merged rarbore2 requested to merge dot_lib into main
3 files
+ 115
75
Compare changes
  • Side-by-side
  • Inline
Files
3
extern crate hercules_ir;
extern crate hercules_ir;
 
extern crate rand;
use std::collections::HashMap;
use std::collections::HashMap;
 
use std::env::temp_dir;
use std::fmt::Write;
use std::fmt::Write;
 
use std::fs::File;
 
use std::io::Write as _;
 
use std::process::Command;
 
 
use rand::Rng;
use self::hercules_ir::*;
use self::hercules_ir::*;
/*
/*
* Top level function to write a module out as a dot graph. Takes references to
* Top level function to compute a dot graph for a module, and immediately
* many analysis results to generate a more informative dot graph.
* 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>(
pub fn write_dot<W: Write>(
module: &ir::Module,
module: &ir::Module,
reverse_postorders: &Vec<Vec<NodeID>>,
reverse_postorders: &Vec<Vec<NodeID>>,
typing: &ModuleTyping,
doms: Option<&Vec<DomTree>>,
doms: &Vec<DomTree>,
fork_join_maps: Option<&Vec<HashMap<NodeID, NodeID>>>,
fork_join_maps: &Vec<HashMap<NodeID, NodeID>>,
plans: Option<&Vec<Plan>>,
plans: &Vec<Plan>,
w: &mut W,
w: &mut W,
) -> std::fmt::Result {
) -> std::fmt::Result {
write_digraph_header(w)?;
write_digraph_header(w)?;
@@ -23,28 +63,38 @@ pub fn write_dot<W: Write>(
@@ -23,28 +63,38 @@ pub fn write_dot<W: Write>(
for function_id in (0..module.functions.len()).map(FunctionID::new) {
for function_id in (0..module.functions.len()).map(FunctionID::new) {
let function = &module.functions[function_id.idx()];
let function = &module.functions[function_id.idx()];
let reverse_postorder = &reverse_postorders[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()];
let mut reverse_postorder_node_numbers = vec![0; function.nodes.len()];
for (idx, id) in reverse_postorder.iter().enumerate() {
for (idx, id) in reverse_postorder.iter().enumerate() {
reverse_postorder_node_numbers[id.idx()] = idx;
reverse_postorder_node_numbers[id.idx()] = idx;
}
}
write_subgraph_header(function_id, module, w)?;
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
// Step 1: draw IR graph itself. This includes all IR nodes and all edges
// between IR nodes.
// between IR nodes.
for partition_idx in 0..plan.num_partitions {
for partition_idx in 0..plan.map_or(1, |plan| plan.num_partitions) {
let partition_color = match plan.partition_devices[partition_idx] {
let partition_color = plan.map(|plan| match plan.partition_devices[partition_idx] {
Device::CPU => "lightblue",
Device::CPU => "lightblue",
Device::GPU => "darkseagreen",
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 nodes_ids.iter() {
for node_id in &partition_to_node_map[partition_idx] {
let node = &function.nodes[node_id.idx()];
let node = &function.nodes[node_id.idx()];
let dst_ty = &module.types[typing[function_id.idx()][node_id.idx()].idx()];
let dst_control = node.is_control();
let dst_strictly_control = node.is_strictly_control();
let dst_control = dst_ty.is_control() || dst_strictly_control;
// Control nodes are dark red, data nodes are dark blue.
// Control nodes are dark red, data nodes are dark blue.
let color = if dst_control { "darkred" } else { "darkblue" };
let color = if dst_control { "darkred" } else { "darkblue" };
@@ -54,14 +104,12 @@ pub fn write_dot<W: Write>(
@@ -54,14 +104,12 @@ pub fn write_dot<W: Write>(
function_id,
function_id,
color,
color,
module,
module,
&plan.schedules[node_id.idx()],
plan.map_or(&vec![], |plan| &plan.schedules[node_id.idx()]),
w,
w,
)?;
)?;
for u in def_use::get_uses(&node).as_ref() {
for u in def_use::get_uses(&node).as_ref() {
let src_ty = &module.types[typing[function_id.idx()][u.idx()].idx()];
let src_control = function.nodes[u.idx()].is_control();
let src_strictly_control = function.nodes[u.idx()].is_strictly_control();
let src_control = src_ty.is_control() || src_strictly_control;
// An edge between control nodes is dashed. An edge between data
// An edge between control nodes is dashed. An edge between data
// nodes is filled. An edge between a control node and a data
// nodes is filled. An edge between a control node and a data
@@ -106,35 +154,39 @@ pub fn write_dot<W: Write>(
@@ -106,35 +154,39 @@ pub fn write_dot<W: Write>(
// Step 2: draw dominance edges in dark green. Don't draw post dominance
// Step 2: draw dominance edges in dark green. Don't draw post dominance
// edges because then xdot lays out the graph strangely.
// edges because then xdot lays out the graph strangely.
let dom = &doms[function_id.idx()];
if let Some(doms) = doms {
for (child_id, (_, parent_id)) in dom.get_underlying_map() {
let dom = &doms[function_id.idx()];
write_edge(
for (child_id, (_, parent_id)) in dom.get_underlying_map() {
*child_id,
write_edge(
function_id,
*child_id,
*parent_id,
function_id,
function_id,
*parent_id,
true,
function_id,
"darkgreen",
true,
"dotted",
"darkgreen",
&module,
"dotted",
w,
&module,
)?;
w,
 
)?;
 
}
}
}
// Step 3: draw fork join edges in dark magenta.
// Step 3: draw fork join edges in dark magenta.
let fork_join_map = &fork_join_maps[function_id.idx()];
if let Some(fork_join_maps) = fork_join_maps {
for (fork_id, join_id) in fork_join_map {
let fork_join_map = &fork_join_maps[function_id.idx()];
write_edge(
for (fork_id, join_id) in fork_join_map {
*join_id,
write_edge(
function_id,
*join_id,
*fork_id,
function_id,
function_id,
*fork_id,
true,
function_id,
"darkmagenta",
true,
"dotted",
"darkmagenta",
&module,
"dotted",
w,
&module,
)?;
w,
 
)?;
 
}
}
}
write_graph_footer(w)?;
write_graph_footer(w)?;
Loading