Skip to content

Conversation

robcasloz
Copy link
Contributor

@robcasloz robcasloz commented Feb 11, 2025

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

Live ranges are first-class IGV entities, meaning that the user can:

  • search, select, and extract them;

search-extract

  • examine their properties in the Properties window or via tooltips;

properties

  • navigate to related IGV entities via a pop-up menu; and

popup

  • program filters that act om them according to their properties.

filters

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

The changeset extends the IGV graph printing logic in HotSpot to emit basic block-level liveness information and live range properties such as associated register mask, score, and type. IGV propagates then the block-level liveness information down to individual nodes. Passing only basic block-level liveness information makes the graph serialization compact, limiting the size increase of the corresponding graphs to around 25%.

The IGV changes do not affect layout performance significantly in the sea-of-nodes view, and only introduce a moderate overhead (of around 10%) when displaying graphs with associated live ranges in the control-flow graph view.

Thanks to Damon Fenacci and Daniel Lundén for providing valuable feedback!

Testing

  • tier1 (windows-x64, linux-x64, linux-aarch64, and macosx-x64; release and debug mode).

  • Tested IGV manually on a few selected graphs. Tested automatically that displaying thousands of graphs using different views and filter combinations does not trigger any assertion failure (by enabling assertions, instrumenting IGV to display parsed graphs eagerly, and running java -Xbatch -XX:-TieredCompilation -XX:PrintIdealGraphLevel=4).


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Warnings

 ⚠️ Patch contains a binary file (src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/liveRange.png)
 ⚠️ Patch contains a binary file (src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectLiveRanges.png)
 ⚠️ Patch contains a binary file (src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectNodes.png)
 ⚠️ Patch contains a binary file (src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/showLiveRanges.png)

Issue

  • JDK-8348645: IGV: visualize live ranges (Enhancement - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/23558/head:pull/23558
$ git checkout pull/23558

Update a local copy of the PR:
$ git checkout pull/23558
$ git pull https://git.openjdk.org/jdk.git pull/23558/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 23558

View PR using the GUI difftool:
$ git pr show -t 23558

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/23558.diff

Using Webrev

Link to Webrev Comment

@robcasloz
Copy link
Contributor Author

Thanks for the report Damon, will investigate!

Commit 0016922 should fix the issue, thanks again.

@dafedafe
Copy link
Contributor

Thanks for the fix Roberto.

I noticed that the live ranges are not saved when saving the graph into an xml file (LIVE_RANGES_ELEMENT and related tags don't seem to be exported in Printer.java). Is this perhaps something you did intentionally (maybe to be added in the future)?

@dafedafe
Copy link
Contributor

@robcasloz, I was a bit puzzled by live ranges with Phi nodes but then I noticed that in the description you mention that they are treated somewhat in a special way:

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.

I thought that variables that are joined by the Phi node are still live at the Phi node. Is this not the case? Or possibly you meant that it is better not to consider them live there (e.g. to reduce the number of live ranges in the block with the Phi node)?

Irrespective of that, would it be feasible to add a "termination dash" at the bottom of the line (e.g. at the bottom of L8)?
image

@robcasloz
Copy link
Contributor Author

I noticed that the live ranges are not saved when saving the graph into an xml file (LIVE_RANGES_ELEMENT and related tags don't seem to be exported in Printer.java). Is this perhaps something you did intentionally (maybe to be added in the future)?

Good catch, thanks! No, I just overlooked this use case. Will fix.

@robcasloz
Copy link
Contributor Author

I thought that variables that are joined by the Phi node are still live at the Phi node. Is this not the case?

No, the usual "multiplex-like" liveness semantics for Phi instructions is to consider the joined variables live-out of their corresponding predecessor blocks and the resulting variable live-in in its block (and defined in parallel with other Phi definitions in the block), see e.g. Definition 4 in Ch. 21.2 in the SSA book draft. This is also in line with C2's handling of Phi nodes in liveness analysis.

Irrespective of that, would it be feasible to add a "termination dash" at the bottom of the line (e.g. at the bottom of L8)?

Yes, that is a good idea, will do, thanks!

@robcasloz
Copy link
Contributor Author

I noticed that the live ranges are not saved when saving the graph into an xml file (LIVE_RANGES_ELEMENT and related tags don't seem to be exported in Printer.java). Is this perhaps something you did intentionally (maybe to be added in the future)?

Good catch, thanks! No, I just overlooked this use case. Will fix.

Done (commit 87b31e9).

@robcasloz
Copy link
Contributor Author

I thought that variables that are joined by the Phi node are still live at the Phi node. Is this not the case?

No, the usual "multiplex-like" liveness semantics for Phi instructions is to consider the joined variables live-out of their corresponding predecessor blocks and the resulting variable live-in in its block (and defined in parallel with other Phi definitions in the block), see e.g. Definition 4 in Ch. 21.2 in the SSA book draft. This is also in line with C2's handling of Phi nodes in liveness analysis.

Irrespective of that, would it be feasible to add a "termination dash" at the bottom of the line (e.g. at the bottom of L8)?

Yes, that is a good idea, will do, thanks!

Done (commit 31e4510). This turned out to be a bit more involved than I thought, please check that the changes meet your expectations. Here is an example of how the initial live ranges related to a phi instruction (106 Phi) are now visualized:

initial-liveness

And here is how the live range L7 resulting from coalescing L18, L34, and L36 is visualized after aggressive coalescing (where SSA is deconstructed):

aggressive-coalescing

@robcasloz
Copy link
Contributor Author

While studying the issues brought up by @dafedafe, I also realized that live ranges of single-block CFGs were not displayed. This is now addressed by commit 51718b9.

@dafedafe
Copy link
Contributor

Done (commit 31e4510). This turned out to be a bit more involved than I thought, please check that the changes meet your expectations.

Nice! I like that the live range end corresponds to the bottom of the block in the Phi case. Thanks @robcasloz!

Copy link
Contributor

@dafedafe dafedafe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor aesthetic thing: I noticed that in phases with no liveness information, the liveness information in each node is replaced by an empty space (instead of nothing):
image
instead of
image

Otherwise it looks good to me (I probably made more of a functionality rather than a code style/semantics kind of review). Thanks again @robcasloz.

@robcasloz
Copy link
Contributor Author

Just a minor aesthetic thing: I noticed that in phases with no liveness information, the liveness information in each node is replaced by an empty space (instead of nothing)

Good catch, thanks Damon! Commit efbde14 should address that, please check that it works as you expect.

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 4, 2025

@robcasloz This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@robcasloz
Copy link
Contributor Author

@robcasloz This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

💓

Copy link
Member

@TobiHartmann TobiHartmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome, thanks a lot for working on this Roberto! I tested it extensively and despite some layout weirdness that we discussed about off-thread and that does not seem to be related to your change, it works well.

I had a quick look at the hotspot changes and they look good to me as well.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Apr 8, 2025
@robcasloz
Copy link
Contributor Author

This is awesome, thanks a lot for working on this Roberto! I tested it extensively and despite some layout weirdness that we discussed about off-thread and that does not seem to be related to your change, it works well.

I had a quick look at the hotspot changes and they look good to me as well.

Thank you very much for reviewing, Tobias! Will have a look at the weird layout issue and re-test before integrating.

@robcasloz
Copy link
Contributor Author

Thanks again for reviewing, Damon and Tobias!
/integrate

@openjdk
Copy link

openjdk bot commented Apr 14, 2025

Going to push as commit 51ce312.
Since your change was applied there have been 903 commits pushed to the master branch:

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Apr 14, 2025
@openjdk openjdk bot closed this Apr 14, 2025
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Apr 14, 2025
@openjdk
Copy link

openjdk bot commented Apr 14, 2025

@robcasloz Pushed as commit 51ce312.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hotspot-compiler hotspot-compiler-dev@openjdk.org integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

5 participants