RFR: 8348645: IGV: visualize live ranges

Roberto Castañeda Lozano rcastanedalo at openjdk.org
Tue Feb 11 14:10:12 UTC 2025


On Tue, 11 Feb 2025 12:42:15 GMT, Johan Sjölen <jsjolen at openjdk.org> wrote:

>> This changeset extends IGV with live range visualization. It introduces live ranges as first-class IGV entities and displays them along with the control-flow graph in the CFG view. Visualizing liveness information should hopefully make C2's register allocator easier to understand, diagnose, debug, and enhance.
>> 
>> Live ranges are visible in C2 phases where liveness information is available, that is, phases `Initial liveness` to `Fix up spills` at IGV print level 4 or greater. For example, running a debug build of the JVM as follows:
>> 
>> 
>> java -Xbatch -XX:CompileCommand=IGVPrintLevel,java.util.HashMap::newNode,4
>> 
>> 
>> produces the following visualization for the `Initial spilling` phase:
>> 
>> ![initial-spilling](https://github.com/user-attachments/assets/1ecf74f5-92a8-4866-b1ec-2323bb0c428e)
>> 
>> Live ranges are first-class IGV entities, meaning that the user can:
>> 
>> - search, select, and extract them;
>> 
>> ![search-extract](https://github.com/user-attachments/assets/8e0dfa59-457f-49cb-b2b5-1d202301c79d)
>> 
>> - examine their properties in the `Properties` window or via tooltips;
>> 
>> ![properties](https://github.com/user-attachments/assets/68d2d23b-b986-4d2e-835c-b661bce0de23)
>> 
>> - navigate to related IGV entities via a pop-up menu; and
>> 
>> ![popup](https://github.com/user-attachments/assets/21de2fef-d36a-42d5-b828-2696d87a18ea)
>> 
>> - program filters that act om them according to their properties.
>> 
>> ![filters](https://github.com/user-attachments/assets/e993b067-d0b8-452c-a885-c4e601e31e1c)
>> 
>> Live ranges are connected to nodes by a use-def relation: a node can define zero or one live ranges, and use multiple live ranges; a live range can be defined and used by multiple nodes. Consequently, a live range in IGV is visible if and only if all its related nodes are visible (fully or semi-transparently). Generally, the start and end of a live range are vertically aligned with the nodes that first define and last use the live range. To reflect accurately the semantics of Phi nodes w.r.t. liveness, the visualization treats live ranges related by Phi nodes specially: live ranges used by a Phi node end at the bottom of the corresponding predecessor basic blocks, whereas live ranges defined by a Phi node start at the top of the node's basic block. The following screenshot shows an example of a Phi node (`48 Phi`) joining live ranges `L8` and `L13` into `L15`:
>> 
>> ![phi](https://github.com/user-attachments/assets/0ef8aa1d-523d-4391-982e-6b74c2016a3c...
>
> src/hotspot/share/opto/idealGraphPrinter.cpp line 1004:
> 
>> 1002:       if (lrg._msize_valid && lrg._degree_valid && lrg.lo_degree()) {
>> 1003:         print_prop("trivial", TRUE_VALUE);
>> 1004:       }
> 
> Hi Roberto,
> 
> Ihis is just a drive-by comment and I know that this style is standard in the IGP source code. However, have you considered re-writing this in the style of setting up the data and then looping over the data in order to print it?
> 
> Here's an example transformation I did from some other code in IGP:
> 
> ```c++
> // Before
>     if (flags & Node::Flag_is_Copy) {
>       print_prop("is_copy", "true");
>     }
>     if (flags & Node::Flag_rematerialize) {
>       print_prop("rematerialize", "true");
>     }
>     if (flags & Node::Flag_needs_anti_dependence_check) {
>       print_prop("needs_anti_dependence_check", "true");
>     }
>     if (flags & Node::Flag_is_macro) {
>       print_prop("is_macro", "true");
>     }
>     if (flags & Node::Flag_is_Con) {
>       print_prop("is_con", "true");
>     }
>     if (flags & Node::Flag_is_cisc_alternate) {
>       print_prop("is_cisc_alternate", "true");
>     }
>     if (flags & Node::Flag_is_dead_loop_safe) {
>       print_prop("is_dead_loop_safe", "true");
>     }
>     if (flags & Node::Flag_may_be_short_branch) {
>       print_prop("may_be_short_branch", "true");
>     }
>     if (flags & Node::Flag_has_call) {
>       print_prop("has_call", "true");
>     }
>     if (flags & Node::Flag_has_swapped_edges) {
>       print_prop("has_swapped_edges", "true");
>     }
> 
> ```c++
> // After
>     struct BKV { int r; const char *name, *v; };
>     const BKV r[] = {
>         {                    flags & Node::Flag_is_Copy,                     "is_copy", "true"},
>         {              flags & Node::Flag_rematerialize,               "rematerialize", "true"},
>         {flags & Node::Flag_needs_anti_dependence_check, "needs_anti_dependence_check", "true"},
>         {                   flags & Node::Flag_is_macro,                    "is_macro", "true"},
>         {                     flags & Node::Flag_is_Con,                      "is_con", "true"},
>         {          flags & Node::Flag_is_cisc_alternate,           "is_cisc_alternate", "true"},
>         {          flags & Node::Flag_is_dead_loop_safe,           "is_dead_loop_safe", "true"},
>         {        flags & Node::Flag_may_be_short_branch,         "may_be_short_branch", "true"},
>         {                   flags & Node::Flag_has_call,                    "has_call", "true"},
>         {          flags & Node::Flag_has_swapped_edges,   ...

Thanks for the suggestion, Johan! I like the proposal but I think it is best left out as a separate RFE, to make sure it is applied consistently to the entire IGV graph printing code. I created [JDK-8349835](https://bugs.openjdk.org/browse/JDK-8349835) for that.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/23558#discussion_r1950919420


More information about the hotspot-compiler-dev mailing list