Skip to content

Commit def907a

Browse files
committed
8354520: IGV: dump contextual information
Reviewed-by: epeter, dfenacci
1 parent 9f8fbf2 commit def907a

File tree

7 files changed

+241
-38
lines changed

7 files changed

+241
-38
lines changed

src/hotspot/share/opto/compile.cpp

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5205,32 +5205,39 @@ IdealGraphPrinter* Compile::_debug_network_printer = nullptr;
52055205

52065206
// Called from debugger. Prints method to the default file with the default phase name.
52075207
// This works regardless of any Ideal Graph Visualizer flags set or not.
5208-
void igv_print() {
5209-
Compile::current()->igv_print_method_to_file();
5208+
// Use in debugger (gdb/rr): p igv_print($sp, $fp, $pc).
5209+
void igv_print(void* sp, void* fp, void* pc) {
5210+
frame fr(sp, fp, pc);
5211+
Compile::current()->igv_print_method_to_file(nullptr, false, &fr);
52105212
}
52115213

52125214
// Same as igv_print() above but with a specified phase name.
5213-
void igv_print(const char* phase_name) {
5214-
Compile::current()->igv_print_method_to_file(phase_name);
5215+
void igv_print(const char* phase_name, void* sp, void* fp, void* pc) {
5216+
frame fr(sp, fp, pc);
5217+
Compile::current()->igv_print_method_to_file(phase_name, false, &fr);
52155218
}
52165219

52175220
// Called from debugger. Prints method with the default phase name to the default network or the one specified with
52185221
// the network flags for the Ideal Graph Visualizer, or to the default file depending on the 'network' argument.
52195222
// This works regardless of any Ideal Graph Visualizer flags set or not.
5220-
void igv_print(bool network) {
5223+
// Use in debugger (gdb/rr): p igv_print(true, $sp, $fp, $pc).
5224+
void igv_print(bool network, void* sp, void* fp, void* pc) {
5225+
frame fr(sp, fp, pc);
52215226
if (network) {
5222-
Compile::current()->igv_print_method_to_network();
5227+
Compile::current()->igv_print_method_to_network(nullptr, &fr);
52235228
} else {
5224-
Compile::current()->igv_print_method_to_file();
5229+
Compile::current()->igv_print_method_to_file(nullptr, false, &fr);
52255230
}
52265231
}
52275232

5228-
// Same as igv_print(bool network) above but with a specified phase name.
5229-
void igv_print(bool network, const char* phase_name) {
5233+
// Same as igv_print(bool network, ...) above but with a specified phase name.
5234+
// Use in debugger (gdb/rr): p igv_print(true, "MyPhase", $sp, $fp, $pc).
5235+
void igv_print(bool network, const char* phase_name, void* sp, void* fp, void* pc) {
5236+
frame fr(sp, fp, pc);
52305237
if (network) {
5231-
Compile::current()->igv_print_method_to_network(phase_name);
5238+
Compile::current()->igv_print_method_to_network(phase_name, &fr);
52325239
} else {
5233-
Compile::current()->igv_print_method_to_file(phase_name);
5240+
Compile::current()->igv_print_method_to_file(phase_name, false, &fr);
52345241
}
52355242
}
52365243

@@ -5242,40 +5249,44 @@ void igv_print_default() {
52425249
// Called from debugger, especially when replaying a trace in which the program state cannot be altered like with rr replay.
52435250
// A method is appended to an existing default file with the default phase name. This means that igv_append() must follow
52445251
// an earlier igv_print(*) call which sets up the file. This works regardless of any Ideal Graph Visualizer flags set or not.
5245-
void igv_append() {
5246-
Compile::current()->igv_print_method_to_file("Debug", true);
5252+
// Use in debugger (gdb/rr): p igv_append($sp, $fp, $pc).
5253+
void igv_append(void* sp, void* fp, void* pc) {
5254+
frame fr(sp, fp, pc);
5255+
Compile::current()->igv_print_method_to_file(nullptr, true, &fr);
52475256
}
52485257

5249-
// Same as igv_append() above but with a specified phase name.
5250-
void igv_append(const char* phase_name) {
5251-
Compile::current()->igv_print_method_to_file(phase_name, true);
5258+
// Same as igv_append(...) above but with a specified phase name.
5259+
// Use in debugger (gdb/rr): p igv_append("MyPhase", $sp, $fp, $pc).
5260+
void igv_append(const char* phase_name, void* sp, void* fp, void* pc) {
5261+
frame fr(sp, fp, pc);
5262+
Compile::current()->igv_print_method_to_file(phase_name, true, &fr);
52525263
}
52535264

5254-
void Compile::igv_print_method_to_file(const char* phase_name, bool append) {
5265+
void Compile::igv_print_method_to_file(const char* phase_name, bool append, const frame* fr) {
52555266
const char* file_name = "custom_debug.xml";
52565267
if (_debug_file_printer == nullptr) {
52575268
_debug_file_printer = new IdealGraphPrinter(C, file_name, append);
52585269
} else {
52595270
_debug_file_printer->update_compiled_method(C->method());
52605271
}
52615272
tty->print_cr("Method %s to %s", append ? "appended" : "printed", file_name);
5262-
_debug_file_printer->print_graph(phase_name);
5273+
_debug_file_printer->print_graph(phase_name, fr);
52635274
}
52645275

5265-
void Compile::igv_print_method_to_network(const char* phase_name) {
5276+
void Compile::igv_print_method_to_network(const char* phase_name, const frame* fr) {
52665277
ResourceMark rm;
52675278
GrowableArray<const Node*> empty_list;
5268-
igv_print_graph_to_network(phase_name, empty_list);
5279+
igv_print_graph_to_network(phase_name, empty_list, fr);
52695280
}
52705281

5271-
void Compile::igv_print_graph_to_network(const char* name, GrowableArray<const Node*>& visible_nodes) {
5282+
void Compile::igv_print_graph_to_network(const char* name, GrowableArray<const Node*>& visible_nodes, const frame* fr) {
52725283
if (_debug_network_printer == nullptr) {
52735284
_debug_network_printer = new IdealGraphPrinter(C);
52745285
} else {
52755286
_debug_network_printer->update_compiled_method(C->method());
52765287
}
52775288
tty->print_cr("Method printed over network stream to IGV");
5278-
_debug_network_printer->print(name, C->root(), visible_nodes);
5289+
_debug_network_printer->print(name, C->root(), visible_nodes, fr);
52795290
}
52805291
#endif
52815292

src/hotspot/share/opto/compile.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -673,13 +673,13 @@ class Compile : public Phase {
673673
void init_igv();
674674
void dump_igv(const char* graph_name, int level = 3) {
675675
if (should_print_igv(level)) {
676-
_igv_printer->print_graph(graph_name);
676+
_igv_printer->print_graph(graph_name, nullptr);
677677
}
678678
}
679679

680-
void igv_print_method_to_file(const char* phase_name = "Debug", bool append = false);
681-
void igv_print_method_to_network(const char* phase_name = "Debug");
682-
void igv_print_graph_to_network(const char* name, GrowableArray<const Node*>& visible_nodes);
680+
void igv_print_method_to_file(const char* phase_name = nullptr, bool append = false, const frame* fr = nullptr);
681+
void igv_print_method_to_network(const char* phase_name = nullptr, const frame* fr = nullptr);
682+
void igv_print_graph_to_network(const char* name, GrowableArray<const Node*>& visible_nodes, const frame* fr);
683683
static IdealGraphPrinter* debug_file_printer() { return _debug_file_printer; }
684684
static IdealGraphPrinter* debug_network_printer() { return _debug_network_printer; }
685685
#endif

src/hotspot/share/opto/idealGraphPrinter.cpp

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#include "opto/idealGraphPrinter.hpp"
2828
#include "opto/machnode.hpp"
2929
#include "opto/parse.hpp"
30+
#include "runtime/arguments.hpp"
3031
#include "runtime/threadCritical.hpp"
3132
#include "runtime/threadSMR.hpp"
33+
#include "utilities/decoder.hpp"
3234
#include "utilities/stringUtils.hpp"
3335

3436
#ifndef PRODUCT
@@ -49,6 +51,13 @@ const char *IdealGraphPrinter::REMOVE_EDGE_ELEMENT = "removeEdge";
4951
const char *IdealGraphPrinter::REMOVE_NODE_ELEMENT = "removeNode";
5052
const char *IdealGraphPrinter::COMPILATION_ID_PROPERTY = "compilationId";
5153
const char *IdealGraphPrinter::COMPILATION_OSR_PROPERTY = "osr";
54+
const char *IdealGraphPrinter::COMPILATION_ARGUMENTS_PROPERTY = "arguments";
55+
const char *IdealGraphPrinter::COMPILATION_MACHINE_PROPERTY = "machine";
56+
const char *IdealGraphPrinter::COMPILATION_CPU_FEATURES_PROPERTY = "cpuFeatures";
57+
const char *IdealGraphPrinter::COMPILATION_VM_VERSION_PROPERTY = "vm";
58+
const char *IdealGraphPrinter::COMPILATION_DATE_TIME_PROPERTY = "dateTime";
59+
const char *IdealGraphPrinter::COMPILATION_PROCESS_ID_PROPERTY = "processId";
60+
const char *IdealGraphPrinter::COMPILATION_THREAD_ID_PROPERTY = "threadId";
5261
const char *IdealGraphPrinter::METHOD_NAME_PROPERTY = "name";
5362
const char *IdealGraphPrinter::METHOD_IS_PUBLIC_PROPERTY = "public";
5463
const char *IdealGraphPrinter::METHOD_IS_STATIC_PROPERTY = "static";
@@ -336,6 +345,42 @@ void IdealGraphPrinter::begin_method() {
336345

337346
print_prop(COMPILATION_ID_PROPERTY, C->compile_id());
338347

348+
stringStream args;
349+
Arguments::print_jvm_args_on(&args);
350+
print_prop(COMPILATION_ARGUMENTS_PROPERTY, args.freeze());
351+
352+
stringStream machine;
353+
buffer[0] = 0;
354+
os::print_summary_info(&machine, buffer, sizeof(buffer) - 1);
355+
print_prop(COMPILATION_MACHINE_PROPERTY, machine.freeze());
356+
357+
print_prop(COMPILATION_CPU_FEATURES_PROPERTY, VM_Version::features_string());
358+
359+
stringStream version;
360+
buffer[0] = 0;
361+
JDK_Version::current().to_string(buffer, sizeof(buffer) - 1);
362+
const char* runtime_name = JDK_Version::runtime_name() != nullptr ?
363+
JDK_Version::runtime_name() : "";
364+
const char* runtime_version = JDK_Version::runtime_version() != nullptr ?
365+
JDK_Version::runtime_version() : "";
366+
const char* vendor_version = JDK_Version::runtime_vendor_version() != nullptr ?
367+
JDK_Version::runtime_vendor_version() : "";
368+
const char* jdk_debug_level = VM_Version::printable_jdk_debug_level() != nullptr ?
369+
VM_Version::printable_jdk_debug_level() : "";
370+
371+
version.print_cr("%s%s%s (%s) (%sbuild %s)", runtime_name,
372+
(*vendor_version != '\0') ? " " : "", vendor_version,
373+
buffer, jdk_debug_level, runtime_version);
374+
print_prop(COMPILATION_VM_VERSION_PROPERTY, version.freeze());
375+
376+
stringStream time;
377+
buffer[0] = 0;
378+
os::print_date_and_time(&time, buffer, sizeof(buffer) - 1);
379+
print_prop(COMPILATION_DATE_TIME_PROPERTY, time.freeze());
380+
381+
print_prop(COMPILATION_PROCESS_ID_PROPERTY, os::current_process_id());
382+
print_prop(COMPILATION_THREAD_ID_PROPERTY, os::current_thread_id());
383+
339384
tail(PROPERTIES_ELEMENT);
340385

341386
_should_send_method = true;
@@ -862,24 +907,91 @@ void IdealGraphPrinter::walk_nodes(Node* start, bool edges) {
862907
}
863908
}
864909

865-
void IdealGraphPrinter::print_graph(const char* name) {
910+
// Whether the stack walk should skip the given frame when producing a C2 stack
911+
// trace. We consider IGV- and debugger-specific frames uninteresting.
912+
static bool should_skip_frame(const char* name) {
913+
return strstr(name, "IdealGraphPrinter") != nullptr ||
914+
strstr(name, "Compile::print_method") != nullptr ||
915+
strstr(name, "Compile::igv_print_graph") != nullptr ||
916+
strstr(name, "PrintBFS") != nullptr ||
917+
strstr(name, "Node::dump_bfs") != nullptr;
918+
}
919+
920+
// Whether the stack walk should be considered done when visiting a certain
921+
// frame. The purpose of walking the stack is producing a C2 trace, so we
922+
// consider all frames below (and including) C2Compiler::compile_method(..)
923+
// uninteresting.
924+
static bool should_end_stack_walk(const char* name) {
925+
return strstr(name, "C2Compiler::compile_method") != nullptr;
926+
}
927+
928+
void IdealGraphPrinter::print_stack(const frame* initial_frame, outputStream* graph_name) {
929+
char buf[O_BUFLEN];
930+
frame fr = initial_frame == nullptr ? os::current_frame() : *initial_frame;
931+
int frame = 0;
932+
for (int count = 0; count < StackPrintLimit && fr.pc() != nullptr; count++) {
933+
int offset;
934+
buf[0] = '\0';
935+
bool found = os::dll_address_to_function_name(fr.pc(), buf, sizeof(buf), &offset);
936+
if (!found || should_end_stack_walk(buf)) {
937+
break;
938+
}
939+
if (!should_skip_frame(buf)) {
940+
stringStream frame_loc;
941+
frame_loc.print("%s", buf);
942+
buf[0] = '\0';
943+
int line_no;
944+
if (Decoder::get_source_info(fr.pc(), buf, sizeof(buf), &line_no, count != 1)) {
945+
frame_loc.print(" (%s:%d)", buf, line_no);
946+
if (graph_name != nullptr) {
947+
// Extract a debug graph name and return.
948+
graph_name->print("%s:%d", buf, line_no);
949+
return;
950+
}
951+
}
952+
if (graph_name == nullptr) {
953+
// Print frame as IGV property and continue to the next frame.
954+
stringStream frame_number_str;
955+
frame_number_str.print("frame %d:", frame);
956+
print_prop(frame_number_str.freeze(), frame_loc.freeze());
957+
frame++;
958+
}
959+
}
960+
fr = frame::next_frame(fr, Thread::current_or_null());
961+
}
962+
}
963+
964+
void IdealGraphPrinter::print_graph(const char* name, const frame* fr) {
866965
ResourceMark rm;
867966
GrowableArray<const Node*> empty_list;
868-
print(name, (Node*) C->root(), empty_list);
967+
print(name, (Node*) C->root(), empty_list, fr);
869968
}
870969

871970
// Print current ideal graph
872-
void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray<const Node*>& visible_nodes) {
971+
void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray<const Node*>& visible_nodes, const frame* fr) {
873972

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

975+
if (name == nullptr) {
976+
stringStream graph_name;
977+
print_stack(fr, &graph_name);
978+
name = graph_name.freeze();
979+
if (strlen(name) == 0) {
980+
name = "Debug";
981+
}
982+
}
983+
876984
// Warning, unsafe cast?
877985
_chaitin = (PhaseChaitin *)C->regalloc();
878986

879987
begin_head(GRAPH_ELEMENT);
880-
print_attr(GRAPH_NAME_PROPERTY, (const char *)name);
988+
print_attr(GRAPH_NAME_PROPERTY, name);
881989
end_head();
882990

991+
head(PROPERTIES_ELEMENT);
992+
print_stack(fr, nullptr);
993+
tail(PROPERTIES_ELEMENT);
994+
883995
head(NODES_ELEMENT);
884996
if (C->cfg() != nullptr) {
885997
// Compute the maximum estimated frequency in the current graph.

src/hotspot/share/opto/idealGraphPrinter.hpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
6767
static const char *ALL_PROPERTY;
6868
static const char *COMPILATION_ID_PROPERTY;
6969
static const char *COMPILATION_OSR_PROPERTY;
70+
static const char *COMPILATION_ARGUMENTS_PROPERTY;
71+
static const char *COMPILATION_MACHINE_PROPERTY;
72+
static const char *COMPILATION_CPU_FEATURES_PROPERTY;
73+
static const char *COMPILATION_VM_VERSION_PROPERTY;
74+
static const char *COMPILATION_DATE_TIME_PROPERTY;
75+
static const char *COMPILATION_PROCESS_ID_PROPERTY;
76+
static const char *COMPILATION_THREAD_ID_PROPERTY;
7077
static const char *METHOD_NAME_PROPERTY;
7178
static const char *BLOCK_NAME_PROPERTY;
7279
static const char *BLOCK_DOMINATOR_PROPERTY;
@@ -110,6 +117,10 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
110117
double _max_freq;
111118
bool _append;
112119

120+
// Walk the native stack and print relevant C2 frames as IGV properties (if
121+
// graph_name == nullptr) or the graph name based on the highest C2 frame (if
122+
// graph_name != nullptr).
123+
void print_stack(const frame* initial_frame, outputStream* graph_name);
113124
void print_method(ciMethod* method, int bci, InlineTree* tree);
114125
void print_inline_tree(InlineTree* tree);
115126
void visit_node(Node* n, bool edges);
@@ -149,8 +160,8 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
149160
void print_inlining();
150161
void begin_method();
151162
void end_method();
152-
void print_graph(const char* name);
153-
void print(const char* name, Node* root, GrowableArray<const Node*>& hidden_nodes);
163+
void print_graph(const char* name, const frame* fr = nullptr);
164+
void print(const char* name, Node* root, GrowableArray<const Node*>& hidden_nodes, const frame* fr = nullptr);
154165
void set_compile(Compile* compile) {C = compile; }
155166
void update_compiled_method(ciMethod* current_method);
156167
};

src/hotspot/share/opto/node.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,8 +1774,8 @@ Node* Node::find(const int idx, bool only_ctrl) {
17741774

17751775
class PrintBFS {
17761776
public:
1777-
PrintBFS(const Node* start, const int max_distance, const Node* target, const char* options, outputStream* st)
1778-
: _start(start), _max_distance(max_distance), _target(target), _options(options), _output(st),
1777+
PrintBFS(const Node* start, const int max_distance, const Node* target, const char* options, outputStream* st, const frame* fr)
1778+
: _start(start), _max_distance(max_distance), _target(target), _options(options), _output(st), _frame(fr),
17791779
_dcc(this), _info_uid(cmpkey, hashkey) {}
17801780

17811781
void run();
@@ -1796,6 +1796,7 @@ class PrintBFS {
17961796
const Node* _target;
17971797
const char* _options;
17981798
outputStream* _output;
1799+
const frame* _frame;
17991800

18001801
// options
18011802
bool _traverse_inputs = false;
@@ -2057,7 +2058,7 @@ void PrintBFS::print() {
20572058
if (_print_igv) {
20582059
Compile* C = Compile::current();
20592060
C->init_igv();
2060-
C->igv_print_graph_to_network("PrintBFS", _print_list);
2061+
C->igv_print_graph_to_network(nullptr, _print_list, _frame);
20612062
}
20622063
} else {
20632064
_output->print_cr("No nodes to print.");
@@ -2102,6 +2103,8 @@ void PrintBFS::print_options_help(bool print_examples) {
21022103
_output->print_cr(" B: print scheduling blocks (if available)");
21032104
_output->print_cr(" $: dump only, no header, no other columns");
21042105
_output->print_cr(" !: show nodes on IGV (sent over network stream)");
2106+
_output->print_cr(" (use preferably with dump_bfs(int, Node*, char*, void*, void*, void*)");
2107+
_output->print_cr(" to produce a C2 stack trace along with the graph dump, see examples below)");
21052108
_output->print_cr("");
21062109
_output->print_cr("recursively follow edges to nodes with permitted visit types,");
21072110
_output->print_cr("on the boundary additionally display nodes allowed in boundary types");
@@ -2151,6 +2154,9 @@ void PrintBFS::print_options_help(bool print_examples) {
21512154
_output->print_cr(" find all paths (A) between two nodes of length at most 8");
21522155
_output->print_cr(" find_node(741)->dump_bfs(7, find_node(741), \"c+A\")");
21532156
_output->print_cr(" find all control loops for this node");
2157+
_output->print_cr(" find_node(741)->dump_bfs(7, find_node(741), \"c+A!\", $sp, $fp, $pc)");
2158+
_output->print_cr(" same as above, but printing the resulting subgraph");
2159+
_output->print_cr(" along with a C2 stack trace on IGV");
21542160
}
21552161
}
21562162

@@ -2409,8 +2415,8 @@ void Node::dump_bfs(const int max_distance, Node* target, const char* options) c
24092415
}
24102416

24112417
// Used to dump to stream.
2412-
void Node::dump_bfs(const int max_distance, Node* target, const char* options, outputStream* st) const {
2413-
PrintBFS bfs(this, max_distance, target, options, st);
2418+
void Node::dump_bfs(const int max_distance, Node* target, const char* options, outputStream* st, const frame* fr) const {
2419+
PrintBFS bfs(this, max_distance, target, options, st, fr);
24142420
bfs.run();
24152421
}
24162422

@@ -2419,6 +2425,13 @@ void Node::dump_bfs(const int max_distance) const {
24192425
dump_bfs(max_distance, nullptr, nullptr);
24202426
}
24212427

2428+
// Call this from debugger, with stack handling register arguments for IGV dumps.
2429+
// Example: p find_node(741)->dump_bfs(7, find_node(741), "c+A!", $sp, $fp, $pc).
2430+
void Node::dump_bfs(const int max_distance, Node* target, const char* options, void* sp, void* fp, void* pc) const {
2431+
frame fr(sp, fp, pc);
2432+
dump_bfs(max_distance, target, options, tty, &fr);
2433+
}
2434+
24222435
// -----------------------------dump_idx---------------------------------------
24232436
void Node::dump_idx(bool align, outputStream* st, DumpConfig* dc) const {
24242437
if (dc != nullptr) {

0 commit comments

Comments
 (0)