Skip to content

Commit 30abf01

Browse files
committed
[GR-70946] Speed up rendering and layout for large graphs
PullRequest: graal/22437
2 parents da57f0f + 8039392 commit 30abf01

File tree

63 files changed

+2178
-534
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2178
-534
lines changed

compiler/mx.compiler/suite.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@
6262
"digest" : "sha512:40c505dd03ca0bb102f1091b89b90672126922f290bd8370eef9a7afc5d9c1e7b5db08c448a0948ef46bf57d850e166813e2d68bf7b1c88a46256d839b6b0201",
6363
"packedResource": True,
6464
},
65+
6566
"IDEALGRAPHVISUALIZER_DIST" : {
66-
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/idealgraphvisualizer/idealgraphvisualizer-1.22-6cb0d3acbb1.zip"],
67-
"digest" : "sha512:8c4795fae203bfa84c40b041fe6d0f46a89bd8b975120d28aea9483eef1c1b63ab685716c1258387c12a255560904284fd0bf9aa947f2efabc4a629148000b5d",
67+
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/idealgraphvisualizer/idealgraphvisualizer-1.23-4543ff4a3e5.zip"],
68+
"digest" : "sha512:2c779c8a01ab4cc7b77e1497ca97641799bb934309ac1306ae8383ab4efdd7af50bbd1bf55438c742e4159b581e69476a2dd8023af0f105433992a35454bdbf0",
6869
"packedResource": True,
6970
},
7071

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graphio/parsing/BinaryReader.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191
public class BinaryReader implements GraphParser, ModelControl {
9292
private static final Logger LOG = Logger.getLogger(BinaryReader.class.getName());
9393

94+
static final boolean TRACE_PARSE_TIME = false;
95+
9496
private final Logger instLog;
9597

9698
private final DataSource dataSource;
@@ -472,15 +474,33 @@ public boolean equals(Object obj) {
472474

473475
public static final class EnumKlass extends Klass {
474476
public final String[] values;
477+
public final EnumValue[] enums;
478+
private volatile int hashCode = 0;
475479

476480
public EnumKlass(String name, String[] values) {
477481
super(name);
478482
this.values = values;
483+
this.enums = new EnumValue[values.length];
484+
for (int i = 0; i < values.length; i++) {
485+
this.enums[i] = new EnumValue(this, i);
486+
}
487+
}
488+
489+
EnumValue get(int ordinal) {
490+
if (ordinal >= 0 && ordinal < enums.length) {
491+
return enums[ordinal];
492+
}
493+
return new EnumValue(this, ordinal);
479494
}
480495

481496
@Override
482497
public int hashCode() {
483-
return super.hash * 31 + Arrays.hashCode(values);
498+
int h = hashCode;
499+
if (h == 0) {
500+
h = Objects.hash(super.hashCode(), Arrays.hashCode(values));
501+
hashCode = h;
502+
}
503+
return h;
484504
}
485505

486506
@Override
@@ -646,7 +666,7 @@ private Object addPoolEntry(Class<?> klass) throws IOException {
646666
case POOL_ENUM: {
647667
EnumKlass enumClass = readPoolObject(EnumKlass.class);
648668
int ordinal = dataSource.readInt();
649-
obj = new EnumValue(enumClass, ordinal);
669+
obj = enumClass.get(ordinal);
650670
break;
651671
}
652672
case POOL_NODE_CLASS: {
@@ -808,6 +828,7 @@ public GraphDocument parse() throws IOException {
808828
hashStack.push(null);
809829

810830
boolean restart = false;
831+
long start = System.nanoTime();
811832
try {
812833
while (true) { // TERMINATION ARGUMENT: finite length of data source will result in
813834
// EOFException eventually.
@@ -831,6 +852,11 @@ public GraphDocument parse() throws IOException {
831852
} finally {
832853
// also terminates the builder
833854
closeDanglingGroups();
855+
if (TRACE_PARSE_TIME) {
856+
long end = System.nanoTime();
857+
System.err.println(((System.nanoTime() - timeStart) / 1_000_000) + " Parsed file in " + ((end - start) / 1_000_000) + " ms");
858+
}
859+
834860
}
835861
return builder.rootDocument();
836862
}
@@ -990,7 +1016,10 @@ private InputGraph parseGraph(String title, boolean toplevel) throws IOException
9901016
}
9911017
}
9921018

1019+
private static final long timeStart = System.nanoTime();
1020+
9931021
private InputGraph parseGraph(int dumpId, String format, Object[] args, boolean toplevel) throws IOException {
1022+
long start = System.nanoTime();
9941023
InputGraph g = builder.startGraph(dumpId, format, args);
9951024
try {
9961025
parseProperties();
@@ -1014,6 +1043,10 @@ private InputGraph parseGraph(int dumpId, String format, Object[] args, boolean
10141043
// we have to finish the graph.
10151044
reporter.popContext();
10161045
g = builder.endGraph();
1046+
if (TRACE_PARSE_TIME) {
1047+
long end = System.nanoTime();
1048+
System.err.println(((System.nanoTime() - timeStart) / 1_000_000) + " Parsed " + dumpId + " " + String.format(format, args) + " in " + ((end - start) / 1000000) + " ms");
1049+
}
10171050
}
10181051
return g;
10191052
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graphio/parsing/Builder.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import jdk.graal.compiler.graphio.parsing.BinaryReader.EnumValue;
3535
import jdk.graal.compiler.graphio.parsing.BinaryReader.Method;
36+
import jdk.graal.compiler.graphio.parsing.TemplateParser.TemplatePart;
3637
import jdk.graal.compiler.graphio.parsing.model.GraphDocument;
3738
import jdk.graal.compiler.graphio.parsing.model.Group;
3839
import jdk.graal.compiler.graphio.parsing.model.InputBlock;
@@ -219,16 +220,23 @@ public String toString() {
219220
final class NodeClass {
220221
public final String className;
221222
public final String nameTemplate;
223+
private final List<TemplatePart> templateParts;
222224
public final List<TypedPort> inputs;
223225
public final List<Port> sux;
226+
private String shortString;
224227

225228
NodeClass(String className, String nameTemplate, List<TypedPort> inputs, List<Port> sux) {
226229
this.className = className;
227230
this.nameTemplate = nameTemplate;
231+
this.templateParts = jdk.graal.compiler.graphio.parsing.TemplateParser.parseTemplate(nameTemplate);
228232
this.inputs = inputs;
229233
this.sux = sux;
230234
}
231235

236+
public List<TemplatePart> getTemplateParts() {
237+
return templateParts;
238+
}
239+
232240
@Override
233241
public String toString() {
234242
return className;
@@ -265,13 +273,18 @@ public boolean equals(Object obj) {
265273
}
266274

267275
String toShortString() {
268-
int lastDot = className.lastIndexOf('.');
269-
String localShortName = className.substring(lastDot + 1);
270-
if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals(CLASS_ENDNODE)) {
271-
return localShortName.substring(0, localShortName.length() - 4);
272-
} else {
273-
return localShortName;
276+
String s = shortString;
277+
if (s == null) {
278+
int lastDot = className.lastIndexOf('.');
279+
String localShortName = className.substring(lastDot + 1);
280+
if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals(CLASS_ENDNODE)) {
281+
s = localShortName.substring(0, localShortName.length() - 4);
282+
} else {
283+
s = localShortName;
284+
}
285+
shortString = s;
274286
}
287+
return shortString;
275288
}
276289
}
277290
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graphio/parsing/ModelBuilder.java

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@
4747
import java.util.Objects;
4848
import java.util.Set;
4949
import java.util.logging.Logger;
50-
import java.util.regex.Matcher;
51-
import java.util.regex.Pattern;
5250

5351
import jdk.graal.compiler.graphio.parsing.BinaryReader.EnumValue;
5452
import jdk.graal.compiler.graphio.parsing.BinaryReader.Method;
@@ -662,6 +660,14 @@ public void endNode(int nodeId) {
662660
PROPNAME_ID,
663661
PROPNAME_IDX, PROPNAME_BLOCK)));
664662

663+
private static boolean isSystemProperty(String key) {
664+
return switch (key) {
665+
case PROPNAME_HAS_PREDECESSOR, PROPNAME_NAME, PROPNAME_CLASS, PROPNAME_ID, PROPNAME_IDX, PROPNAME_BLOCK ->
666+
true;
667+
default -> false;
668+
};
669+
}
670+
665671
@Override
666672
public void setGroupName(String name, String shortName) {
667673
assert folder instanceof Group;
@@ -684,7 +690,7 @@ protected final void reportProgress() {
684690
@Override
685691
public void setNodeName(NodeClass nodeClass) {
686692
assert currentNode != null;
687-
getProperties().setProperty(PROPNAME_NAME, createName(nodeClass, nodeEdges, nodeClass.nameTemplate));
693+
getProperties().setProperty(PROPNAME_NAME, createName(nodeClass, nodeEdges));
688694
getProperties().setProperty(PROPNAME_CLASS, nodeClass.className);
689695
switch (nodeClass.className) {
690696
case "BeginNode":
@@ -696,35 +702,38 @@ public void setNodeName(NodeClass nodeClass) {
696702
}
697703
}
698704

699-
static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{([pi])#([a-zA-Z0-9$_]+)(/([lms]))?}");
700-
701-
private String createName(NodeClass nodeClass, List<EdgeInfo> edges, String template) {
702-
if (template.isEmpty()) {
705+
private String createName(NodeClass nodeClass, List<EdgeInfo> edges) {
706+
if (nodeClass.nameTemplate.isEmpty()) {
703707
return nodeClass.toShortString();
704708
}
705-
Matcher m = TEMPLATE_PATTERN.matcher(template);
706-
StringBuilder sb = new StringBuilder();
709+
710+
StringBuilder sb = new StringBuilder(nodeClass.nameTemplate.length());
707711
Properties p = getProperties();
708-
while (m.find()) {
709-
String name = m.group(2);
710-
String type = m.group(1);
711-
String result;
712+
List<TemplateParser.TemplatePart> templateParts = nodeClass.getTemplateParts();
713+
for (TemplateParser.TemplatePart template : templateParts) {
714+
if (!template.isReplacement) {
715+
sb.append(template.value);
716+
continue;
717+
}
718+
String name = template.name;
719+
String type = template.type;
712720
switch (type) {
713721
case "i":
714-
StringBuilder inputString = new StringBuilder();
722+
boolean first = true;
715723
for (EdgeInfo edge : edges) {
716724
if (edge.label.startsWith(name) && (name.length() == edge.label.length() || edge.label.charAt(name.length()) == '[')) {
717-
if (inputString.length() > 0) {
718-
inputString.append(", ");
725+
if (!first) {
726+
sb.append(", ");
719727
}
720-
inputString.append(edge.from);
728+
first = false;
729+
sb.append(edge.from);
721730
}
722731
}
723-
result = inputString.toString();
724732
break;
725733
case "p":
726734
Object prop = p.get(name);
727-
String length = m.group(4);
735+
String length = template.length;
736+
String result;
728737
if (prop == null) {
729738
result = "?";
730739
} else if (length != null && prop instanceof LengthToString lengthProp) {
@@ -735,36 +744,21 @@ private String createName(NodeClass nodeClass, List<EdgeInfo> edges, String temp
735744
case "m":
736745
result = lengthProp.toString(Length.M);
737746
break;
738-
default:
739747
case "l":
748+
default:
740749
result = lengthProp.toString(Length.L);
741750
break;
742751
}
743752
} else {
744753
result = prop.toString();
745754
}
755+
sb.append(result);
746756
break;
747757
default:
748-
result = "#?#";
758+
sb.append("#?#");
749759
break;
750760
}
751-
752-
// Escape '\' and '$' to not interfere with the regular expression.
753-
StringBuilder newResult = new StringBuilder();
754-
for (int i = 0; i < result.length(); ++i) {
755-
char c = result.charAt(i);
756-
if (c == '\\') {
757-
newResult.append("\\\\");
758-
} else if (c == '$') {
759-
newResult.append("\\$");
760-
} else {
761-
newResult.append(c);
762-
}
763-
}
764-
result = newResult.toString();
765-
m.appendReplacement(sb, result);
766761
}
767-
m.appendTail(sb);
768762
return sb.toString();
769763
}
770764

@@ -775,7 +769,7 @@ public void setNodeProperty(String key, Object value) {
775769
assert currentNode != null;
776770
String k = key;
777771
if (!(value instanceof InputGraph)) {
778-
if (SYSTEM_PROPERTIES.contains(key)) {
772+
if (isSystemProperty(key)) {
779773
k = NOT_DATA + k;
780774
}
781775
setProperty(k, value);
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.graal.compiler.graphio.parsing;
26+
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import java.util.regex.Matcher;
30+
import java.util.regex.Pattern;
31+
32+
public class TemplateParser {
33+
private static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{([pi])#([a-zA-Z0-9$_]+)(/([lms]))?}");
34+
35+
public static List<TemplatePart> parseTemplate(String template) {
36+
List<TemplatePart> parts = new ArrayList<>();
37+
Matcher m = TEMPLATE_PATTERN.matcher(template);
38+
int lastEnd = 0;
39+
while (m.find()) {
40+
if (m.start() > lastEnd) {
41+
parts.add(new TemplatePart(template.substring(lastEnd, m.start())));
42+
}
43+
String name = m.group(2);
44+
String type = m.group(1);
45+
switch (type) {
46+
case "i":
47+
parts.add(new TemplatePart(name, type, null));
48+
break;
49+
case "p":
50+
String length = m.group(4);
51+
parts.add(new TemplatePart(name, type, length));
52+
break;
53+
default:
54+
parts.add(new TemplatePart("#?#"));
55+
break;
56+
}
57+
lastEnd = m.end();
58+
}
59+
if (lastEnd < template.length()) {
60+
parts.add(new TemplatePart(template.substring(lastEnd)));
61+
}
62+
return parts;
63+
}
64+
65+
public static class TemplatePart {
66+
public final String value;
67+
public final boolean isReplacement;
68+
public final String name;
69+
public final String type;
70+
public final String length;
71+
72+
public TemplatePart(String name, String type, String length) {
73+
this.name = name;
74+
this.type = type;
75+
this.length = length;
76+
this.value = null;
77+
this.isReplacement = true;
78+
}
79+
80+
public TemplatePart(String value) {
81+
this.value = value;
82+
this.isReplacement = false;
83+
name = null;
84+
type = null;
85+
length = null;
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)