RFR: 8283775: VM support for graph querying in debugger with BFS traversal and node filtering

Emanuel Peter duke at openjdk.java.net
Mon May 2 07:07:21 UTC 2022


I implemented VM support for BFS traversal of IR nodes, where one can filter for input/output edges, and the node-type (control / data / memory). If one specifies the `target` node, we find a shortest path between `root` and `target`. With the `filter` string one can easily select which node types to traverse.

`void print_bfs(Node* root, const uint max_distance, Node* target, const char* filter)`

While a sufficient summary and description is in the comments above the function definition, I want to explain some useful use-cases here.

Please let me know if you would find this helpful, or if you have any feedback to improve it.
Thanks, Emanuel

**1. Better dump()**
The function is similar to `dump()`, we can also follow input / output edges up to a certain distance. There are a few improvements/added features:

1. Display the distance to the specified node. This way I can quickly assess how many nodes I have at a certain distance, and I can traverse edges from one distance to the next. The parent column shows the node one step closer to the BFS root.
2. Node filtering with types taken from `type->category()` help one limit traversal to control, data or memory flow. The categories are the same as in IGV.
3. Probably controversial: coloring of node types in terminal. By default it is off. May not work on all terminals. But I find it very useful to quickly separate memory, data and control - just as in IGV - but in my terminal!
4. After matching, we create Mach nodes from the IR nodes. For most Mach nodes, there is an associated old node. Often an assert is triggered for Mach nodes, but the graph already breaks in the IR graph. It is thus very helpful to have the old node idx displayed.
5. I also display the head node idx of the block a Mach node is scheduled for. This can be helpful if one gets bad dominance asserts, and needs to see why the blocks were scheduled in a bad way.

Example:

(rr) p print_bfs(find_node(7011), 2, 0, "cdmox+")
No target: perform BFS.
dis   par dir dump
-------------------------------------------
  0  7011 +d  7011  Bool  === _  7010  [[ 7012 ]] [gt] 
  1  7011 +d  7010  CmpI  === _  216  213  [[ 7011 ]] 
  2  7010 +d  216  AddI  === _  385  386  [[ 9066  7020  7010  385 ]] 
  2  7010 +d  213  Phi  ===  6987  378  6982  [[ 278  .... ]]


Example with Mach nodes:

(rr) p print_bfs(load, 2, 0, "cdmox+#OB")
No target: perform BFS.
dis  head  idom dep   old   par dir dump
-------------------------------------------
  0   314   315  18  o260   144 +d  144  loadF  ===  314  136  143  [[ 138  270 ]]
  1   314   315  18     _   144 +c  314  Region  ===  314  97  [[ 314  95  144 ]] 
  1   316   317  16  o305   144 +m  136  MachProj  ===  105  [[ 135  137  143  144  139  145  190  221  240  258 ]]
  1   316   317  16  o285   144 +d  143  loadN  === _  136  69  [[ 137  144  103  100  202 ]]
  2   315   316  17  o311   314 +c  97  IfTrue  ===  98  [[ 314 ]]
  2   316   317  16  o306   136 +x  105  membar_acquire  ===  316  0  147  0  0  [[ 136  104 ]]
  2    49     1   2   o10   143 +d  69  MachProj  ===  49  [[ 67  132  134  143  145  146  151  169  50  4  247 ]]


**2. Find loop body**
When I find myself in a loop, I try to localize the loop head and end, and map out at least one path between them.
`print_bfs(loop_end, 20, loop_head, "cox+")`
This provides us with a shortest path, given this path has a distance of at most 20.

Example:

(rr) p print_bfs(find_node(357), 30, find_node(587), "cox+")
Find shortest path: 357 -> 587.

Backtrace target.
disdir dump
-------------------------------------
 21 +c  587  CountedLoop  ===  587  361  121  [[ 587  589  603  604 ]]
 20 +x  589  MemBarAcquire  ===  587  1  603  1  1  [[ 588  590 ]] 
 19 +c  590  Proj  ===  589  [[ 591 ]] 
 18 +c  591  If  ===  590  574  [[ 592  605 ]]
 17 +c  592  IfTrue  ===  591  [[ 576  593 ]]
 16 +c  593  RangeCheck  ===  592  566  [[ 594  607 ]]
...
  2 +c  296  RangeCheck  ===  295  272  [[ 299  316 ]]
  1 +c  299  IfTrue  ===  296  [[ 258  265  357 ]]
  0   c  357  CountedLoopEnd  ===  299  356  [[ 358  121 ]] [lt]

-------------

Commit messages:
 - some white spaces fixed
 - fixing up root in shortest path backtracking
 - 8283775: VM support for graph querying in debugger with BFS traversal and node filtering

Changes: https://git.openjdk.java.net/jdk/pull/8468/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=8468&range=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8283775
  Stats: 295 lines in 1 file changed: 295 ins; 0 del; 0 mod
  Patch: https://git.openjdk.java.net/jdk/pull/8468.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/8468/head:pull/8468

PR: https://git.openjdk.java.net/jdk/pull/8468


More information about the hotspot-compiler-dev mailing list