1
Fork 0

Add a -Zdump-drop-tracking-cfg debugging flag

This is useful for debugging drop-tracking; previously, you had to recompile
rustc from source and manually add a call to `write_graph_to_file`. This
makes the option more discoverable and configurable at runtime.

I also took the liberty of making the labels for the CFG nodes much easier to read:
previously, they looked like `id(2), local_id: 48`, now they look like
```
expr from_config (hir_id=HirId { owner: DefId(0:10 ~ default_struct_update[79f9]::foo), local_id: 2})
```
This commit is contained in:
Joshua Nelson 2022-06-26 06:19:32 -05:00
parent 0e1a6fb463
commit 483ee1f147
4 changed files with 33 additions and 19 deletions

View file

@ -649,6 +649,7 @@ fn test_debugging_options_tracking_hash() {
untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
untracked!(dont_buffer_diagnostics, true); untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true); untracked!(dump_dep_graph, true);
untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir, Some(String::from("abc")));
untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dataflow, true);
untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_dir, String::from("abc"));

View file

@ -1245,6 +1245,8 @@ options! {
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \ "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
(default: no)"), (default: no)"),
dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump drop-tracking control-flow graph as a `.dot` file (default: no)"),
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED], dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump MIR state to file. "dump MIR state to file.
`val` is used to select which passes and functions to dump. For example: `val` is used to select which passes and functions to dump. For example:

View file

@ -33,6 +33,9 @@ pub(super) fn build_control_flow_graph<'tcx>(
intravisit::walk_body(&mut drop_range_visitor, body); intravisit::walk_body(&mut drop_range_visitor, body);
drop_range_visitor.drop_ranges.process_deferred_edges(); drop_range_visitor.drop_ranges.process_deferred_edges();
if let Some(filename) = &tcx.sess.opts.debugging_opts.dump_drop_tracking_cfg {
super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
}
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries) (drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
} }

View file

@ -2,6 +2,7 @@
//! flow graph when needed for debugging. //! flow graph when needed for debugging.
use rustc_graphviz as dot; use rustc_graphviz as dot;
use rustc_middle::ty::TyCtxt;
use super::{DropRangesBuilder, PostOrderId}; use super::{DropRangesBuilder, PostOrderId};
@ -9,22 +10,35 @@ use super::{DropRangesBuilder, PostOrderId};
/// ///
/// It is not normally called, but is kept around to easily add debugging /// It is not normally called, but is kept around to easily add debugging
/// code when needed. /// code when needed.
#[allow(dead_code)] pub(super) fn write_graph_to_file(
pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) { drop_ranges: &DropRangesBuilder,
dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap(); filename: &str,
tcx: TyCtxt<'_>,
) {
dot::render(
&DropRangesGraph { drop_ranges, tcx },
&mut std::fs::File::create(filename).unwrap(),
)
.unwrap();
} }
impl<'a> dot::GraphWalk<'a> for DropRangesBuilder { struct DropRangesGraph<'a, 'tcx> {
drop_ranges: &'a DropRangesBuilder,
tcx: TyCtxt<'tcx>,
}
impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> {
type Node = PostOrderId; type Node = PostOrderId;
type Edge = (PostOrderId, PostOrderId); type Edge = (PostOrderId, PostOrderId);
fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> { fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
self.nodes.iter_enumerated().map(|(i, _)| i).collect() self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect()
} }
fn edges(&'a self) -> dot::Edges<'a, Self::Edge> { fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
self.nodes self.drop_ranges
.nodes
.iter_enumerated() .iter_enumerated()
.flat_map(|(i, node)| { .flat_map(|(i, node)| {
if node.successors.len() == 0 { if node.successors.len() == 0 {
@ -45,7 +59,7 @@ impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
} }
} }
impl<'a> dot::Labeller<'a> for DropRangesBuilder { impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
type Node = PostOrderId; type Node = PostOrderId;
type Edge = (PostOrderId, PostOrderId); type Edge = (PostOrderId, PostOrderId);
@ -60,18 +74,12 @@ impl<'a> dot::Labeller<'a> for DropRangesBuilder {
fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> { fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
dot::LabelText::LabelStr( dot::LabelText::LabelStr(
format!( self.drop_ranges
"{:?}, local_id: {}", .post_order_map
n, .iter()
self.post_order_map .find(|(_hir_id, &post_order_id)| post_order_id == *n)
.iter() .map_or("<unknown>".into(), |(hir_id, _)| self.tcx.hir().node_to_string(*hir_id))
.find(|(_hir_id, &post_order_id)| post_order_id == *n) .into(),
.map_or("<unknown>".into(), |(hir_id, _)| format!(
"{}",
hir_id.local_id.index()
))
)
.into(),
) )
} }
} }