Skip to content
Permalink
Browse files
8261336: IGV: enhance default filters
Add filters to color and hide parts of the graph based on node categories or
estimated execution frequency, and simplify remaining filters.

Co-authored-by: Christian Hagedorn <chagedorn@openjdk.org>
Reviewed-by: vlivanov, chagedorn, thartmann
  • Loading branch information
robcasloz and chhagedorn committed Feb 16, 2021
1 parent 3f8819c commit 16bd7d381f498ed659d2b1b372458d86fbbef275
Showing with 331 additions and 83 deletions.
  1. +42 −1 src/hotspot/share/opto/idealGraphPrinter.cpp
  2. +2 −1 src/hotspot/share/opto/idealGraphPrinter.hpp
  3. +68 −1 src/hotspot/share/opto/type.cpp
  4. +12 −1 src/hotspot/share/opto/type.hpp
  5. +3 −5 src/utils/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/ConnectionFilter.java
  6. +0 −28 src/utils/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml
  7. +3 −2 src/utils/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Connection.java
  8. +21 −14 ...s/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/color.filter
  9. +23 −0 ...aphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/colorFrequency.filter
  10. +41 −0 ...alGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/extract-colors.py
  11. +3 −0 ...lGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideControl.filter
  12. +5 −0 ...hVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideControlEdges.filter
  13. +3 −0 ...dealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideData.filter
  14. +5 −0 ...raphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideDataEdges.filter
  15. +3 −0 ...alGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideMemory.filter
  16. +5 −0 ...phVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideMemoryEdges.filter
  17. +3 −0 ...ealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideMixed.filter
  18. +5 −0 ...aphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideMixedEdges.filter
  19. +3 −0 ...ealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideOther.filter
  20. +5 −0 ...aphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/hideOtherEdges.filter
  21. +12 −9 ...phVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/onlyControlFlow.filter
  22. +0 −8 .../IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/remove.filter
  23. +13 −0 ...alGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/structural.filter
  24. +44 −12 src/utils/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/layer.xml
  25. +7 −1 src/utils/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2021, 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
@@ -30,6 +30,7 @@
#include "opto/parse.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/stringUtils.hpp"

#ifndef PRODUCT

@@ -378,9 +379,39 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
print_prop("block", C->cfg()->get_block(0)->_pre_order);
} else {
print_prop("block", block->_pre_order);
// Print estimated execution frequency, normalized within a [0,1] range.
buffer[0] = 0;
stringStream freq(buffer, sizeof(buffer) - 1);
// Higher precision has no practical effect in visualizations.
freq.print("%.8f", block->_freq / _max_freq);
assert(freq.size() < sizeof(buffer), "size in range");
// Enforce dots as decimal separators, as required by IGV.
StringUtils::replace_no_expand(buffer, ",", ".");
print_prop("frequency", buffer);
}
}

switch (t->category()) {
case Type::Category::Data:
print_prop("category", "data");
break;
case Type::Category::Memory:
print_prop("category", "memory");
break;
case Type::Category::Mixed:
print_prop("category", "mixed");
break;
case Type::Category::Control:
print_prop("category", "control");
break;
case Type::Category::Other:
print_prop("category", "other");
break;
case Type::Category::Undef:
print_prop("category", "undef");
break;
}

const jushort flags = node->flags();
if (flags & Node::Flag_is_Copy) {
print_prop("is_copy", "true");
@@ -649,6 +680,16 @@ void IdealGraphPrinter::print(const char *name, Node *node) {
VectorSet temp_set;

head(NODES_ELEMENT);
if (C->cfg() != NULL) {
// Compute the maximum estimated frequency in the current graph.
_max_freq = 1.0e-6;
for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) {
Block* block = C->cfg()->get_block(i);
if (block->_freq > _max_freq) {
_max_freq = block->_freq;
}
}
}
walk_nodes(node, false, &temp_set);
tail(NODES_ELEMENT);

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2021, 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
@@ -92,6 +92,7 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
PhaseChaitin* _chaitin;
bool _traverse_outs;
Compile *C;
double _max_freq;

void print_method(ciMethod *method, int bci, InlineTree *tree);
void print_inline_tree(InlineTree *tree);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@@ -1113,6 +1113,73 @@ void Type::dump_stats() {
}
#endif

//------------------------------category---------------------------------------
#ifndef PRODUCT
Type::Category Type::category() const {
const TypeTuple* tuple;
switch (base()) {
case Type::Int:
case Type::Long:
case Type::Half:
case Type::NarrowOop:
case Type::NarrowKlass:
case Type::Array:
case Type::VectorA:
case Type::VectorS:
case Type::VectorD:
case Type::VectorX:
case Type::VectorY:
case Type::VectorZ:
case Type::AnyPtr:
case Type::RawPtr:
case Type::OopPtr:
case Type::InstPtr:
case Type::AryPtr:
case Type::MetadataPtr:
case Type::KlassPtr:
case Type::Function:
case Type::Return_Address:
case Type::FloatTop:
case Type::FloatCon:
case Type::FloatBot:
case Type::DoubleTop:
case Type::DoubleCon:
case Type::DoubleBot:
return Category::Data;
case Type::Memory:
return Category::Memory;
case Type::Control:
return Category::Control;
case Type::Top:
case Type::Abio:
case Type::Bottom:
return Category::Other;
case Type::Bad:
case Type::lastype:
return Category::Undef;
case Type::Tuple:
// Recursive case. Return CatMixed if the tuple contains types of
// different categories (e.g. CallStaticJavaNode's type), or the specific
// category if all types are of the same category (e.g. IfNode's type).
tuple = is_tuple();
if (tuple->cnt() == 0) {
return Category::Undef;
} else {
Category first = tuple->field_at(0)->category();
for (uint i = 1; i < tuple->cnt(); i++) {
if (tuple->field_at(i)->category() != first) {
return Category::Mixed;
}
}
return first;
}
default:
assert(false, "unmatched base type: all base types must be categorized");
}
return Category::Undef;
}
#endif

//------------------------------typerr-----------------------------------------
void Type::typerr( const Type *t ) const {
#ifndef PRODUCT
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@@ -364,6 +364,17 @@ class Type {
}
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
static void dump_stats();
// Groups of types, for debugging and visualization only.
enum class Category {
Data,
Memory,
Mixed, // Tuples with types of different categories.
Control,
Other, // {Type::Top, Type::Abio, Type::Bottom}.
Undef // {Type::Bad, Type::lastype}, for completeness.
};
// Return the category of this type.
Category category() const;

static const char* str(const Type* t);
#endif
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2021, 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
@@ -63,10 +63,8 @@ public void apply(Diagram diagram) {
for (Figure f : figures) {
for (OutputSlot os : f.getOutputSlots()) {
for (Connection c : os.getConnections()) {
if (figures.contains(c.getInputSlot().getFigure())) {
c.setStyle(rule.getLineStyle());
c.setColor(rule.getLineColor());
}
c.setStyle(rule.getLineStyle());
c.setColor(rule.getLineColor());
}
}
}
@@ -2,33 +2,5 @@
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
<folder name="Filters">
<file name="Coloring" url="filters/color.filter">
<attr name="enabled" boolvalue="true"/>
</file>


<file name="Stamp Coloring" url="filters/stampColor.filter">
<attr name="enabled" boolvalue="false"/>
</file>

<file name="Probability Coloring" url="filters/probability.filter">
<attr name="enabled" boolvalue="false"/>
</file>

<file name="Call Graph Coloring" url="filters/callgraph.filter">
<attr name="enabled" boolvalue="false"/>
</file>

<file name="Reduce Edges" url="filters/reduceEdges.filter">
<attr name="enabled" boolvalue="true"/>
</file>

<file name="Remove State" url="filters/removeState.filter">
<attr name="enabled" boolvalue="false"/>
</file>

<file name="Remove Floating" url="filters/removeFloating.filter">
<attr name="enabled" boolvalue="false"/>
</file>
</folder>
</filesystem>
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2021, 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
@@ -46,7 +46,8 @@ public enum ConnectionStyle {

NORMAL,
DASHED,
BOLD
BOLD,
INVISIBLE
}
private InputSlot inputSlot;
private OutputSlot outputSlot;
@@ -1,18 +1,25 @@
colorize("name", ".*", yellow);
colorize("name", "Catch.*", blue);
colorize("name", "Region|Loop|CountedLoop|Root", red);
colorize("name", "CProj|IfFalse|IfTrue|JProj|CatchProj", magenta);
colorize("name", "Con.*", orange);
colorize("name", "Parm|Proj", lightGray);
var mixedNodeColor = java.awt.Color.decode("#ffaabb");
var controlNodeColor = java.awt.Color.decode("#ee8866");
var otherNodeColor = java.awt.Color.decode("#eedd88");
var dataNodeColor = java.awt.Color.decode("#adcbea");
var memoryNodeColor = java.awt.Color.decode("#babb00");

// Nodes with bci
colorize("bci", "..*", magenta);
var mixedEdgeColor = java.awt.Color.decode("#ff7f99");
var controlEdgeColor = java.awt.Color.decode("#e75828");
var otherEdgeColor = java.awt.Color.decode("#dfc025");
var dataEdgeColor = java.awt.Color.decode("#3178c2");
var memoryEdgeColor = java.awt.Color.decode("#828200");

colorize("category", "data", dataNodeColor);
colorize("category", "memory", memoryNodeColor);
colorize("category", "mixed", mixedNodeColor);
colorize("category", "control", controlNodeColor);
colorize("category", "other", otherNodeColor);

// Line style
var f = new ColorFilter("Line Style filter");
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("type", "int:")), null, Color.BLUE, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("type", "control")), null, Color.RED, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("type", "memory")), null, Color.GREEN, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("type", "tuple:")), null, Color.MAGENTA, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("type", "bottom")), null, Color.LIGHT_GRAY, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data")), null, dataEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "memory")), null, memoryEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "mixed")), null, mixedEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control")), null, controlEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "other")), null, otherEdgeColor, null));
f.apply(graph);
@@ -0,0 +1,23 @@
// Color nodes by estimated execution frequency. Applies only when control-flow
// graph information is available (from "Global Code Motion" on).

// These colors are generated by running:
// $ python3 extract-colors.py --steps 10 --colormap coolwarm
var step0Color = java.awt.Color.decode("#3b4cc0");
var step1Color = java.awt.Color.decode("#5977e3");
var step2Color = java.awt.Color.decode("#7b9ff9");
var step3Color = java.awt.Color.decode("#9ebeff");
var step4Color = java.awt.Color.decode("#c0d4f5");
var step5Color = java.awt.Color.decode("#dddcdc");
var step6Color = java.awt.Color.decode("#f2cbb7");
var step7Color = java.awt.Color.decode("#f7ac8e");
var step8Color = java.awt.Color.decode("#ee8468");
var step9Color = java.awt.Color.decode("#d65244");
var step10Color = java.awt.Color.decode("#b40426");

var colors = [step0Color, step1Color, step2Color, step3Color, step4Color, step5Color, step6Color, step7Color, step8Color, step9Color, step10Color]
var fractions = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

// The max value is set to 1.01 instead of 1.0 to workaround a (numerical?)
// issue where nodes with frequencies close (but not equal to) 1.0 are not colored.
colorizeGradientCustom("frequency", 0.0, 1.01, "logarithmic", colors, fractions, 1024);
@@ -0,0 +1,41 @@
#!/usr/bin/python3
#
# Copyright (c) 2021, 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
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.

import matplotlib.cm
import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument('--steps', type=int, default=10)
parser.add_argument('--colormap', default='coolwarm')
args = parser.parse_args()

cmap = matplotlib.cm.get_cmap(args.colormap)
n = args.steps

for step in range(n + 1):
point = step / float(n)
rgb = tuple([int(round(c * 255)) for c in cmap(point)[0:3]])
hex = '#%02x%02x%02x' % rgb
print("var step" + str(step) + "Color" + " = java.awt.Color.decode(\"" + \
hex + "\");")
@@ -0,0 +1,3 @@
var f = new RemoveFilter("Hide control subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control"))));
f.apply(graph);
@@ -0,0 +1,5 @@
var f = new ConnectionFilter("Hide control edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
@@ -0,0 +1,3 @@
var f = new RemoveFilter("Hide data subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data"))));
f.apply(graph);
@@ -0,0 +1,5 @@
var f = new ConnectionFilter("Hide data edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
@@ -0,0 +1,3 @@
var f = new RemoveFilter("Hide memory subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "memory"))));
f.apply(graph);

1 comment on commit 16bd7d3

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 16bd7d3 Feb 16, 2021

Choose a reason for hiding this comment

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

Please sign in to comment.