8315604: IGV: dump and visualize node bottom and phase types

Co-authored-by: Tobias Holenstein <tholenstein@openjdk.org>
Reviewed-by: thartmann, chagedorn, tholenstein
This commit is contained in:
Roberto Castañeda Lozano 2023-10-02 07:03:40 +00:00
parent 8fcf70e931
commit 207819a05e
10 changed files with 145 additions and 48 deletions

View File

@ -374,9 +374,28 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
#ifndef PRODUCT
Compile::current()->_in_dump_cnt++;
print_prop(NODE_NAME_PROPERTY, (const char *)node->Name());
print_prop("idx", node->_idx);
const Type *t = node->bottom_type();
print_prop("type", t->msg());
print_prop("idx", node->_idx);
if (t->category() != Type::Category::Control &&
t->category() != Type::Category::Memory) {
// Print detailed type information for nodes whose type is not trivial.
buffer[0] = 0;
stringStream bottom_type_stream(buffer, sizeof(buffer) - 1);
t->dump_on(&bottom_type_stream);
print_prop("bottom_type", buffer);
if (C->types() != nullptr && C->matcher() == nullptr) {
// Phase types maintained during optimization (GVN, IGVN, CCP) are
// available and valid (not in code generation phase).
const Type* pt = (*C->types())[node->_idx];
if (pt != nullptr) {
buffer[0] = 0;
stringStream phase_type_stream(buffer, sizeof(buffer) - 1);
pt->dump_on(&phase_type_stream);
print_prop("phase_type", buffer);
}
}
}
if (C->cfg() != nullptr) {
Block* block = C->cfg()->get_block_for_node(node);

View File

@ -89,7 +89,7 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
outputStream *_output;
ciMethod *_current_method;
int _depth;
char buffer[128];
char buffer[512];
bool _should_send_method;
PhaseChaitin* _chaitin;
bool _traverse_outs;

View File

@ -124,11 +124,10 @@ class Type_Array : public AnyObj {
uint _max;
const Type **_types;
void grow( uint i ); // Grow array node to fit
const Type *operator[] ( uint i ) const // Lookup, or null for not mapped
{ return (i<_max) ? _types[i] : (Type*)nullptr; }
friend class PhaseValues;
public:
Type_Array(Arena *a) : _a(a), _max(0), _types(0) {}
const Type *operator[] ( uint i ) const // Lookup, or null for not mapped
{ return (i<_max) ? _types[i] : (Type*)nullptr; }
const Type *fast_lookup(uint i) const{assert(i<_max,"oob");return _types[i];}
// Extend the mapping: index i maps to Type *n.
void map( uint i, const Type *n ) { if( i>=_max ) grow(i); _types[i] = n; }

View File

@ -26,23 +26,23 @@ package com.sun.hotspot.igv.filter;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.Selector;
import java.util.function.UnaryOperator;
import java.util.function.Function;
import java.util.List;
public class EditPropertyFilter extends AbstractFilter {
private String name;
private Selector selector;
private final String inputPropertyName;
private final String[] inputPropertyNames;
private final String outputPropertyName;
private final UnaryOperator<String> editFunction;
private final Function<String[], String> editFunction;
public EditPropertyFilter(String name, Selector selector,
String inputPropertyName, String outputPropertyName,
UnaryOperator<String> editFunction) {
String[] inputPropertyNames, String outputPropertyName,
Function<String[], String> editFunction) {
this.name = name;
this.selector = selector;
this.inputPropertyName = inputPropertyName;
this.inputPropertyNames = inputPropertyNames;
this.outputPropertyName = outputPropertyName;
this.editFunction = editFunction;
}
@ -55,9 +55,12 @@ public class EditPropertyFilter extends AbstractFilter {
@Override
public void apply(Diagram diagram) {
List<Figure> list = selector.selected(diagram);
String[] inputVals = new String[inputPropertyNames.length];
for (Figure f : list) {
String inputVal = f.getProperties().get(inputPropertyName);
String outputVal = editFunction.apply(inputVal);
for (int i = 0; i < inputPropertyNames.length; i++) {
inputVals[i] = f.getProperties().get(inputPropertyNames[i]);
}
String outputVal = editFunction.apply(inputVals);
f.getProperties().setProperty(outputPropertyName, outputVal);
}
}

View File

@ -190,15 +190,15 @@ var white = Color.white;
// function that takes as input the old property value and returns the new
// property value.
function editSameProperty(selector, propertyName, editFunction) {
var f = new EditPropertyFilter("", selector, propertyName, propertyName, editFunction);
var f = new EditPropertyFilter("", selector, [propertyName], propertyName, editFunction);
f.apply(graph);
}
// Update the value of the given property ('outputPropertyName') in the selected
// nodes according to a function that takes as input the value of a possibly
// different property ('inputPropertyName') and returns the new property value.
function editProperty(selector, inputPropertyName, outputPropertyName, editFunction) {
var f = new EditPropertyFilter("", selector, inputPropertyName, outputPropertyName, editFunction);
// nodes according to a function that takes as input the values of multiple
// properties ('inputPropertyNames') and returns the new property value.
function editProperty(selector, inputPropertyNames, outputPropertyName, editFunction) {
var f = new EditPropertyFilter("", selector, inputPropertyNames, outputPropertyName, editFunction);
f.apply(graph);
}

View File

@ -3,7 +3,8 @@
// combination with "Simplify graph".
// Pretty-print Bool nodes to be shown as output slots.
function replaceComparisonWithSign(dump_spec) {
function replaceComparisonWithSign(propertyValues) {
dump_spec = propertyValues[0]
var comparison = dump_spec.replace('[','').replace(']','')
switch (comparison) {
case "eq": return "=";
@ -23,21 +24,22 @@ editSameProperty(and([matches("name", "ConP|ConN"), matches("dump_spec", "#.*NUL
function(t) {return "null";});
// Pretty-print CatchProj nodes.
function catchProjShortText(con) {
function catchProjShortText(propertyValues) {
con = propertyValues[0]
switch (con) {
case "0": return "F"; // fall-through
case "1": return "T"; // throw
default: return "?";
}
}
editProperty(matches("name", "CatchProj"), "con", "short_name", catchProjShortText);
editProperty(matches("name", "CatchProj"), ["con"], "short_name", catchProjShortText);
// Add short text to inlined Mach data parameters.
editProperty(and([matches("name", "MachProj"),
matches("category", "data"),
successorOf(matches("name", "Start"))]),
"dump_spec", "short_name",
function(dump_spec) {return dump_spec;});
["dump_spec"], "short_name",
function(dump_spec) {return dump_spec[0];});
// Condense inputs in all nodes.
var anyNode = matches("name", ".*");

View File

@ -14,10 +14,10 @@ function callJavaInfo(dump_spec, regularPos, trapPos) {
}
return "trap: " + tm[2];
}
editProperty(matches("name", "CallStaticJava|CallDynamicJava|CallJava"), "dump_spec", "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec, 2, 2);});
editProperty(matches("name", "CallStaticJavaDirect|CallDynamicJavaDirect"), "dump_spec", "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec, 1, 3);});
editProperty(matches("name", "CallStaticJava|CallDynamicJava|CallJava"), ["dump_spec"], "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec[0], 2, 2);});
editProperty(matches("name", "CallStaticJavaDirect|CallDynamicJavaDirect"), ["dump_spec"], "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec[0], 1, 3);});
function callLeafInfo(dump_spec, pos) {
dump_components = split_string(dump_spec);
@ -26,21 +26,7 @@ function callLeafInfo(dump_spec, pos) {
}
return dump_components[pos];
}
editProperty(matches("name", "CallLeaf|CallLeafNoFP"), "dump_spec", "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec, 1);});
editProperty(matches("name", "CallLeafDirect|CallLeafDirectVector|CallLeafNoFPDirect"), "dump_spec", "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec, 0);});
// Add extra line to exception creation nodes with the name of the exception.
function exceptionInfo(dump_spec) {
dump_spec2 = dump_spec.replace('#','')
dump_components = split_string(dump_spec2);
if (dump_components.length < 1) {
return null;
}
// dump_components[0] has a form like e.g. java/lang/NumberFormatException:NotNull,
// we want to return only the simple class name ("NumberFormatException").
simple_classname = dump_components[0].split("/").pop();
return simple_classname.split(":")[0];
}
editProperty(matches("name", "CreateEx|CreateException"), "dump_spec", "extra_label", exceptionInfo);
editProperty(matches("name", "CallLeaf|CallLeafNoFP"), ["dump_spec"], "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec[0], 1);});
editProperty(matches("name", "CallLeafDirect|CallLeafDirectVector|CallLeafNoFPDirect"), ["dump_spec"], "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec[0], 0);});

View File

@ -0,0 +1,72 @@
// This filter appends simplified type information to the (possibly already
// existing) extra-label line.
// If the phase type is available, show it. If the bottom type is available and
// differs from the bottom type, show it too (prefixed with 'B:').
// Simplify a reference type of the form
// "[5:]my/package/Class (package1/Class1,package2/Class2,..)"
// into
// "[5:]Class"
function simplify_reference_type(type) {
// Clean up interface lists in reference types.
var m = /(.*)\(.*\)(.*)/.exec(type);
if (m != null && typeof m[1] != 'undefined' && typeof m[2] != 'undefined') {
type = m[1] + m[2];
}
// Remove package name in reference types.
var m2 = /(\d+:)?.*\/(.*)/.exec(type);
if (m2 != null && typeof m2[2] != 'undefined') {
type = (typeof m2[1] != 'undefined' ? m2[1] : "") + m2[2];
}
return type;
}
// Remove fixed input types for calls and simplify references.
function simplifyType(type) {
var callTypeStart = "{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address";
if (type.startsWith(callTypeStart)) {
// Exclude types of the first five outputs of call-like nodes.
type = type.replace(callTypeStart, "").replace("}", "");
prefix = ", ";
if (type.startsWith(prefix)) {
type = type.slice(prefix.length);
}
components = type.split(", ");
for (i = 0; i < components.length; i++) {
components[i] = simplify_reference_type(components[i]);
}
type = "{" + components.join(", ") + "}";
} else {
type = simplify_reference_type(type);
}
type = type.replace(">=", "≥").replace("<=", "≤");
return type;
}
// Merge a possibly existing extra label, bottom type, and phase type into a
// new, single extra label.
function mergeAndAppendTypeInfo(extra_label, bottom_type, phase_type) {
if (phase_type == null && bottom_type == null) {
return extra_label;
}
type = "";
// Always show phase type, if available.
if (phase_type != null) {
type += simplifyType(phase_type);
}
// Show bottom type, if available and different from phase type.
if (bottom_type != null && bottom_type != phase_type) {
if (phase_type != null) {
type += " | ";
}
type += "B: ";
type += simplifyType(bottom_type);
}
new_extra_label = extra_label == null ? "" : (extra_label + " ");
return new_extra_label + type;
}
editProperty(not(or([matches("bottom_type", "bottom"),
matches("bottom_type", "abIO")])),
["extra_label", "bottom_type", "phase_type"], "extra_label",
function(propertyValues) {return mergeAndAppendTypeInfo(propertyValues[0], propertyValues[1], propertyValues[2]);});

View File

@ -15,11 +15,15 @@
</file>
<file name="Show custom node info.js" url="filters/customNodeInfo.filter">
<attr name="enabled" boolvalue="true"/>
<attr name="after" stringvalue="Color by execution frequency"/>
<attr name="after" stringvalue="Show node warnings"/>
</file>
<file name="Show types.js" url="filters/showTypes.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Show custom node info"/>
</file>
<file name="Simplify graph.js" url="filters/simplifyGraph.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Show custom node info"/>
<attr name="after" stringvalue="Show types"/>
</file>
<file name="Condense graph.js" url="filters/condenseGraph.filter">
<attr name="enabled" boolvalue="false"/>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -84,6 +84,16 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
return middleWidget.isHitAt(localLocation);
}
private void formatExtraLabel(boolean selected) {
// If the figure contains an extra label, use a light italic font to
// differentiate it from the regular label.
if (getFigure().getProperties().get("extra_label") != null) {
LabelWidget extraLabelWidget = labelWidgets.get(labelWidgets.size() - 1);
extraLabelWidget.setFont(Diagram.FONT.deriveFont(Font.ITALIC));
extraLabelWidget.setForeground(selected ? getTextColor() : Color.DARK_GRAY);
}
}
public FigureWidget(final Figure f, DiagramScene scene) {
super(scene);
@ -139,6 +149,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
lw.setBorder(BorderFactory.createEmptyBorder());
lw.setCheckClipping(false);
}
formatExtraLabel(false);
if (getFigure().getWarning() != null) {
ImageWidget warningWidget = new ImageWidget(scene, warningSign);
@ -194,6 +205,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
for (LabelWidget labelWidget : labelWidgets) {
labelWidget.setFont(font);
}
formatExtraLabel(state.isSelected());
repaint();
}