Skip to content

Conversation

@robcasloz
Copy link
Contributor

@robcasloz robcasloz commented Apr 17, 2025

This changeset extends the IGV graph dumps with additional properties that ease tracing the dumps back to the context in which they were produced. The changeset dumps, for every compilation, the following additional properties:

  • JVM arguments
  • platform information
  • JVM version information
  • date and time
  • process ID
  • (compiler) thread ID

compilation-properties

Additionally, the changeset produces and dumps the C2 stack trace from which each graph is dumped:

c2-stack-trace

This should be particularly useful in an interactive context, where the user steps through C2 code using a debugger and dumps graphs at different points. To produce a stack trace in this context, the usual debugger-entry C2 functions (igv_print, igv_append, Node::dump_bfs, ...) are extended with extra arguments to specify the stack handling registers (stack pointer, frame pointer, and program counter):

c2-stack-trace-from-gdb

The inconvenience of manually specifying the stack handling registers can be addressed by hiding them in debugger user-defined commands, e.g.:

define igv
  p igv_print(true, $sp, $fp, $pc)
end

define igv_node
  p find_node($arg0)->dump_bfs(0, 0, "!", $sp, $fp, $pc)
end

Thanks to @TobiHartmann for providing useful feedback!

Testing

  • tier1 (windows-x64, linux-x64, linux-aarch64, macosx-x64, and macosx-aarch64; release and debug mode).
  • Tested interactive usage manually via gdb and rr on linux-x64.
  • Tested automatically that dumping thousands of graphs does not trigger any assertion failure.

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

Issue

  • JDK-8354520: IGV: dump contextual information (Enhancement - P4)

Reviewers

Reviewers without OpenJDK IDs

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 24724

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

Using diff file

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

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 17, 2025

👋 Welcome back rcastanedalo! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Apr 17, 2025

@robcasloz This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8354520: IGV: dump contextual information

Reviewed-by: epeter, dfenacci

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 288 new commits pushed to the master branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk
Copy link

openjdk bot commented Apr 17, 2025

@robcasloz The following label will be automatically applied to this pull request:

  • hotspot-compiler

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the hotspot-compiler hotspot-compiler-dev@openjdk.org label Apr 17, 2025
@robcasloz robcasloz marked this pull request as ready for review April 17, 2025 14:09
@openjdk openjdk bot added the rfr Pull request is ready for review label Apr 17, 2025
@mlbridge
Copy link

mlbridge bot commented Apr 17, 2025

Webrevs

Copy link
Contributor

@mhaessig mhaessig left a comment

Choose a reason for hiding this comment

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

Thank you for working on this and continually improving IGV!

I found two typos, but otherwise it looks good. I also tested printing to IGV from rr and the new features work as advertised.

Perhaps you could update the dump_bfs help with a comment about the new arguments?


The JVM provides some entry functions to dump graphs from a debugger such as
`gdb` or `rr`, see the different variants of `igv_print` and `igv_append` in
`compile.cpp`. In combination with the IGV network interface, these functions
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
`compile.cpp`. In combination with the IGV network interface, these functions
[`compile.cpp`](src/hotspot/share/opto/compile.cpp). In combination with the
IGV network interface, these functions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion, but what is the value of adding such a link here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I often find them helpful to find the files a readme is referring to, so I tend to add them. But it's up to you whether you like them as well 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough, so the relative link will resolve correctly and point to the actual compile.cpp file on GitHub?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the link now (commit 8193767d). Turns out GitHub would treat it, by default, as relative to the directory where the README.md file is placed, so I had to prefix it with / to make it relative to the root of the repo.

@robcasloz
Copy link
Contributor Author

I found two typos, but otherwise it looks good. I also tested printing to IGV from rr and the new features work as advertised.

Thanks for trying out and reviewing, Manuel!

Perhaps you could update the dump_bfs help with a comment about the new arguments?

Done (commit d65ecdb), let me know if that works for you.

I also made a minor correction to the IGV documentation (commit 86fdc67).

@robcasloz
Copy link
Contributor Author

Commit dd1ad6a documents how to dump the C2 stack trace when using lldb (default debugger on macOS platforms). Thanks @dafedafe for reporting and helping out!

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.

Thanks a lot for adding this feature @robcasloz.

Compile* C = Compile::current();
C->init_igv();
C->igv_print_graph_to_network("PrintBFS", _print_list);
C->igv_print_graph_to_network(nullptr, _print_list, _frame);
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose you removed "PrintBFS" to make the graph name be "Debug" like the other ones and make it easier to handle name and stack printing right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right.

@robcasloz
Copy link
Contributor Author

Thanks a lot for adding this feature @robcasloz.

Thanks for reviewing, Damon!

Copy link
Contributor

@eme64 eme64 left a comment

Choose a reason for hiding this comment

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

Nice work @robcasloz !

I just left a few suggestions below, but I think they are basically all nits / optional :)

IdealGraphPrinter* Compile::_debug_network_printer = nullptr;

// Called from debugger. Prints method to the default file with the default phase name.
// This works regardless of any Ideal Graph Visualizer flags set or not.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// This works regardless of any Ideal Graph Visualizer flags set or not.
// This works regardless of any Ideal Graph Visualizer flags set or not.
// Use in debugger (gdb / rr): p igv_print($sp, $fp, $pc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).

// the network flags for the Ideal Graph Visualizer, or to the default file depending on the 'network' argument.
// This works regardless of any Ideal Graph Visualizer flags set or not.
void igv_print(bool network) {
void igv_print(bool network, void* sp, void* fp, void* pc) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
void igv_print(bool network, void* sp, void* fp, void* pc) {
// Use in debugger (gdb / rr): p igv_print(true, $sp, $fp, $pc)
void igv_print(bool network, void* sp, void* fp, void* pc) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).

}
}

// Same as igv_print(bool network) above but with a specified phase name.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Same as igv_print(bool network) above but with a specified phase name.
// Same as igv_print(bool network, void* sp, void* fp, void* pc) above but with a specified phase name.
// Use in debugger (gdb / rr): p igv_print(true, "MyPhase", $sp, $fp, $pc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).


// Called from debugger, especially when replaying a trace in which the program state cannot be altered like with rr replay.
// A method is appended to an existing default file with the default phase name. This means that igv_append() must follow
// an earlier igv_print(*) call which sets up the file. This works regardless of any Ideal Graph Visualizer flags set or not.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// an earlier igv_print(*) call which sets up the file. This works regardless of any Ideal Graph Visualizer flags set or not.
// an earlier igv_print(*) call which sets up the file. This works regardless of any Ideal Graph Visualizer flags set or not.
// Use in debugger (gdb / rr): p igv_append($sp, $fp, $pc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).

Compile::current()->igv_print_method_to_file(nullptr, true, &fr);
}

// Same as igv_append() above but with a specified phase name.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Same as igv_append() above but with a specified phase name.
// Same as igv_append(void* sp, void* fp, void* pc) above but with a specified phase name.
// Use in debugger (gdb / rr): p igv_append("MyPhase", $sp, $fp, $pc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).

Thread* _current = Thread::current_or_null();
int count = 0;
int frame = 0;
while (count++ < StackPrintLimit && fr.pc() != nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be formulated as a for loop?

Suggested change
while (count++ < StackPrintLimit && fr.pc() != nullptr) {
for (int count = 0; count < StackPrintLimit && fr.pc() != nullptr; count++) {

Just an idea, totally optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks (commit 9cd331d).


if (!_current_method || !_should_send_method || node == nullptr) return;

frame current = fr == nullptr ? os::current_frame() : *fr;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
frame current = fr == nullptr ? os::current_frame() : *fr;
frame current_frame = fr == nullptr ? os::current_frame() : *fr;

Just to make sure there is no confusion with _current_method.
Optional, up to you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also: what is the implication of having the frame object on the stack, rather than a pointer to it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, never mind, I see it all over the runtime code base. Seems ok, though I'm a little uneasy about it. But not your problem, I guess ;)

// Walk the native stack and print relevant C2 frames as IGV properties (if
// graph_name == nullptr) or the graph name based on the highest C2 frame (if
// graph_name != nullptr).
void print_stack(frame fr, outputStream* graph_name);
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you passing this frame by value on purpose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I refactored this code in commit 6fa328e to pass the initial frame by reference.

const Node* _target;
const char* _options;
outputStream* _output;
frame* _frame;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be const, like the other pointers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 3c3108b), thanks.

dump_bfs(max_distance, nullptr, nullptr);
}

// Call this from debugger, with stack handling register arguments for IGV dumps.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Call this from debugger, with stack handling register arguments for IGV dumps.
// Call this from debugger, with stack handling register arguments for IGV dumps.
// Example: p find_node(741)->dump_bfs(7, find_node(741), "c+A!", $sp, $fp, $pc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (commit 6b8e659).

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

Nice work @robcasloz !

I just left a few suggestions below, but I think they are basically all nits / optional :)

Thanks Emanuel, I addressed your comments and suggestions, including dumping of CPU features (as seen by C2, i.e. Abstract_VM_Version::_features_string).

Copy link
Contributor

@eme64 eme64 left a comment

Choose a reason for hiding this comment

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

@robcasloz Amazing, thanks for the updates :)

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

Manuel, Damon, and Emanuel: thanks again for reviewing!

@robcasloz
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented May 6, 2025

Going to push as commit def907a.
Since your change was applied there have been 303 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 May 6, 2025
@openjdk openjdk bot closed this May 6, 2025
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels May 6, 2025
@openjdk
Copy link

openjdk bot commented May 6, 2025

@robcasloz Pushed as commit def907a.

💡 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.

4 participants