Skip to content

Commit 3e78a81

Browse files
peter-hofercstancu
authored andcommitted
[GR-58088] Improve layer build times and memory usage.
PullRequest: graal/18802
2 parents a07c67c + 17df3ea commit 3e78a81

File tree

13 files changed

+228
-92
lines changed

13 files changed

+228
-92
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,7 @@ private Object decode(String encoded) {
516516
deferred = new ArrayList<>();
517517
lineNum = 0;
518518

519-
List<String> lines = encoded.lines().toList();
520-
Iterator<String> iter = lines.iterator();
519+
Iterator<String> iter = encoded.lines().iterator();
521520
try {
522521
while (iter.hasNext()) {
523522
String line = iter.next();
@@ -707,7 +706,8 @@ private Object decode(String encoded) {
707706
d.runnable().run();
708707
}
709708
} catch (Throwable e) {
710-
throw new GraalError(e, "Error on line %d: %s", lineNum, lines.get(lineNum - 1));
709+
String line = encoded.lines().skip(lineNum - 1).findFirst().get();
710+
throw new GraalError(e, "Error on line %d: %s", lineNum, line);
711711
} finally {
712712
deferred = null;
713713
lineNum = -1;

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/json/JsonParser.java

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.io.IOException;
2929
import java.io.Reader;
3030
import java.io.StringReader;
31+
import java.nio.CharBuffer;
3132
import java.util.ArrayList;
3233
import java.util.List;
3334

@@ -64,13 +65,18 @@ public final class JsonParser {
6465
private final Reader source;
6566

6667
// Current reading position within source
67-
private int pos = 0;
68+
private int pos;
6869
// Current line number, used for error reporting.
6970
private int line = 0;
7071
// Position of the start of the current line in source, used for error reporting.
7172
private int beginningOfLine = 0;
7273
// Next character to be scanned, obtained from source
7374
private int next;
75+
/**
76+
* Characters following 'next'. Managing our own buffer instead of using {@link BufferedReader}
77+
* avoids unnecessary locking that becomes significant when getting individual characters.
78+
*/
79+
private final CharBuffer buffer = CharBuffer.allocate(8192).limit(0);
7480

7581
private static final int EOF = -1;
7682

@@ -90,12 +96,12 @@ public JsonParser(String source) throws IOException {
9096
/**
9197
* Creates a new {@link JsonParser} that reads characters from {@code source}.
9298
*
93-
* @param source character stream containing JSON text. Will be adapted internally through a
94-
* {@link BufferedReader}.
99+
* @param source character reader containing JSON text.
95100
*/
96101
public JsonParser(Reader source) throws IOException {
97-
this.source = new BufferedReader(source);
98-
next = source.read();
102+
this.source = source;
103+
next();
104+
this.pos = 0;
99105
}
100106

101107
/**
@@ -475,8 +481,10 @@ private Number parseNumber() throws IOException {
475481
}
476482

477483
private Object parseKeyword(final String keyword, final Object value) throws IOException {
478-
if (!read(keyword.length()).equals(keyword)) {
479-
throw expectedError(pos, "json literal", "ident");
484+
for (int i = 0; i < keyword.length(); i++) {
485+
if (next() != keyword.charAt(i)) {
486+
throw expectedError(pos, "json literal", "ident");
487+
}
480488
}
481489
return value;
482490
}
@@ -487,22 +495,19 @@ private int peek() {
487495

488496
private int next() throws IOException {
489497
int cur = next;
490-
next = source.read();
498+
if (buffer.isEmpty()) {
499+
buffer.clear(); // resets position and limit
500+
if (source.read(buffer) == -1) { // eof
501+
next = -1;
502+
return cur;
503+
}
504+
buffer.flip();
505+
}
506+
next = buffer.get();
491507
pos++;
492508
return cur;
493509
}
494510

495-
private String read(int length) throws IOException {
496-
char[] buffer = new char[length];
497-
498-
buffer[0] = (char) peek();
499-
source.read(buffer, 1, length - 1);
500-
pos += length - 1;
501-
next();
502-
503-
return String.valueOf(buffer);
504-
}
505-
506511
private void skipWhiteSpace() throws IOException {
507512
while (next != -1) {
508513
switch (peek()) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ public void cleanupAfterAnalysis() {
232232

233233
universe.getHeapScanner().cleanupAfterAnalysis();
234234
universe.getHeapVerifier().cleanupAfterAnalysis();
235+
if (universe.getImageLayerLoader() != null) {
236+
universe.getImageLayerLoader().cleanupAfterAnalysis();
237+
}
235238
}
236239

237240
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@
105105
import java.lang.annotation.Annotation;
106106
import java.lang.reflect.Executable;
107107
import java.lang.reflect.Field;
108+
import java.nio.ByteBuffer;
109+
import java.nio.channels.FileChannel;
108110
import java.nio.file.Path;
109111
import java.util.HashMap;
110112
import java.util.List;
@@ -135,6 +137,7 @@
135137
import com.oracle.graal.pointsto.util.AnalysisFuture;
136138
import com.oracle.svm.util.ReflectionUtil;
137139

140+
import jdk.graal.compiler.core.common.NumUtil;
138141
import jdk.graal.compiler.core.common.SuppressFBWarnings;
139142
import jdk.graal.compiler.debug.GraalError;
140143
import jdk.graal.compiler.nodes.EncodedGraph;
@@ -302,7 +305,7 @@ public class ImageLayerLoader {
302305
protected final Map<Integer, AnalysisMethod> methods = new ConcurrentHashMap<>();
303306
protected final Map<Integer, AnalysisField> fields = new ConcurrentHashMap<>();
304307
protected final Map<Integer, ImageHeapConstant> constants = new ConcurrentHashMap<>();
305-
private final List<Path> loadPaths;
308+
private final List<FilePaths> loadPaths;
306309
private final Map<Integer, BaseLayerType> baseLayerTypes = new ConcurrentHashMap<>();
307310
private final Map<Integer, Integer> typeToHubIdentityHashCode = new ConcurrentHashMap<>();
308311
private final Map<Integer, BaseLayerMethod> baseLayerMethods = new ConcurrentHashMap<>();
@@ -332,22 +335,22 @@ record FieldIdentifier(String tid, String name) {
332335
protected HostedValuesProvider hostedValuesProvider;
333336

334337
protected EconomicMap<String, Object> jsonMap;
338+
protected FileChannel graphsChannel;
335339

336340
private long imageHeapSize;
337341

342+
public record FilePaths(Path snapshot, Path snapshotGraphs) {
343+
}
344+
338345
public ImageLayerLoader() {
339346
this(new ImageLayerSnapshotUtil(), List.of());
340347
}
341348

342-
public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List<Path> loadPaths) {
349+
public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List<FilePaths> loadPaths) {
343350
this.imageLayerSnapshotUtil = imageLayerSnapshotUtil;
344351
this.loadPaths = loadPaths;
345352
}
346353

347-
public List<Path> getLoadPaths() {
348-
return loadPaths;
349-
}
350-
351354
public AnalysisUniverse getUniverse() {
352355
return universe;
353356
}
@@ -360,16 +363,18 @@ public void setImageLayerLoaderHelper(ImageLayerLoaderHelper imageLayerLoaderHel
360363
this.imageLayerLoaderHelper = imageLayerLoaderHelper;
361364
}
362365

363-
/**
364-
* Note this code is not thread safe.
365-
*/
366-
protected void loadJsonMap() {
366+
/** This code is not thread safe. */
367+
protected void openFilesAndLoadJsonMap() {
367368
assert loadPaths.size() == 1 : "Currently only one path is supported for image layer loading " + loadPaths;
368369
if (jsonMap == null) {
369-
for (Path layerPath : loadPaths) {
370-
try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(layerPath.toFile()))) {
371-
Object json = new JsonParser(inputStreamReader).parse();
372-
jsonMap = cast(json);
370+
for (FilePaths paths : loadPaths) {
371+
try {
372+
graphsChannel = FileChannel.open(paths.snapshotGraphs);
373+
374+
try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(paths.snapshot.toFile()))) {
375+
Object json = new JsonParser(inputStreamReader).parse();
376+
jsonMap = cast(json);
377+
}
373378
} catch (IOException e) {
374379
throw AnalysisError.shouldNotReachHere("Error during image layer snapshot loading", e);
375380
}
@@ -378,10 +383,20 @@ protected void loadJsonMap() {
378383
}
379384

380385
public void loadLayerAnalysis() {
381-
loadJsonMap();
386+
openFilesAndLoadJsonMap();
382387
loadLayerAnalysis0();
383388
}
384389

390+
public void cleanupAfterAnalysis() {
391+
if (graphsChannel != null) {
392+
try {
393+
graphsChannel.close();
394+
} catch (IOException e) {
395+
throw AnalysisError.shouldNotReachHere(e);
396+
}
397+
}
398+
}
399+
385400
/**
386401
* Initializes the {@link ImageLayerLoader}.
387402
*/
@@ -792,7 +807,7 @@ public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) {
792807

793808
public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) {
794809
EconomicMap<String, Object> methodData = getMethodData(analysisMethod);
795-
String encodedAnalyzedGraph = get(methodData, ANALYSIS_PARSED_GRAPH_TAG);
810+
String encodedAnalyzedGraph = readEncodedGraph(methodData, ANALYSIS_PARSED_GRAPH_TAG);
796811
Boolean intrinsic = get(methodData, INTRINSIC_TAG);
797812
/*
798813
* Methods without a persisted graph are folded and static methods.
@@ -802,21 +817,44 @@ public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod)
802817
if (encodedAnalyzedGraph != null) {
803818
EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph);
804819
if (hasStrengthenedGraph(analysisMethod)) {
805-
loadAllAnalysisElements(get(methodData, STRENGTHENED_GRAPH_TAG));
820+
loadAllAnalysisElements(readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG));
806821
}
807822
return new AnalysisParsedGraph(analyzedGraph, intrinsic);
808823
}
809824
throw AnalysisError.shouldNotReachHere("The method " + analysisMethod + " does not have a graph from the base layer");
810825
}
811826

827+
private String readEncodedGraph(EconomicMap<String, Object> methodData, String elementIdentifier) {
828+
String location = get(methodData, elementIdentifier);
829+
int closingBracketAt = location.length() - 1;
830+
AnalysisError.guarantee(location.charAt(0) == '@' && location.charAt(closingBracketAt) == ']', "Location must start with '@' and end with ']': %s", location);
831+
int openingBracketAt = location.indexOf('[', 1, closingBracketAt);
832+
AnalysisError.guarantee(openingBracketAt < closingBracketAt, "Location does not contain '[' at expected location: %s", location);
833+
long offset;
834+
long nbytes;
835+
try {
836+
offset = Long.parseUnsignedLong(location.substring(1, openingBracketAt));
837+
nbytes = Long.parseUnsignedLong(location.substring(openingBracketAt + 1, closingBracketAt));
838+
} catch (NumberFormatException e) {
839+
throw AnalysisError.shouldNotReachHere("Location contains invalid positive integer(s): " + location);
840+
}
841+
ByteBuffer bb = ByteBuffer.allocate(NumUtil.safeToInt(nbytes));
842+
try {
843+
graphsChannel.read(bb, offset);
844+
} catch (IOException e) {
845+
throw AnalysisError.shouldNotReachHere("Failed reading a graph from location: " + location, e);
846+
}
847+
return new String(bb.array(), ImageLayerWriter.GRAPHS_CHARSET);
848+
}
849+
812850
public boolean hasStrengthenedGraph(AnalysisMethod analysisMethod) {
813851
EconomicMap<String, Object> methodData = getMethodData(analysisMethod);
814852
return get(methodData, STRENGTHENED_GRAPH_TAG) != null;
815853
}
816854

817855
public void setStrengthenedGraph(AnalysisMethod analysisMethod) {
818856
EconomicMap<String, Object> methodData = getMethodData(analysisMethod);
819-
String encodedAnalyzedGraph = get(methodData, STRENGTHENED_GRAPH_TAG);
857+
String encodedAnalyzedGraph = readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG);
820858
EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph);
821859
processGraph(analyzedGraph);
822860
analysisMethod.setAnalyzedGraph(analyzedGraph);
@@ -827,17 +865,19 @@ protected void processGraph(EncodedGraph encodedGraph) {
827865

828866
}
829867

830-
protected void loadAllAnalysisElements(String encoding) {
831-
for (String line : encoding.lines().toList()) {
832-
if (line.contains(PointsToAnalysisType.class.getName())) {
833-
getAnalysisType(getId(line));
834-
} else if (line.contains(PointsToAnalysisMethod.class.getName())) {
835-
getAnalysisMethod(getId(line));
836-
} else if (line.contains(PointsToAnalysisField.class.getName())) {
837-
getAnalysisField(getId(line));
838-
} else if (line.contains(ImageHeapInstance.class.getName()) || line.contains(ImageHeapObjectArray.class.getName()) || line.contains(ImageHeapPrimitiveArray.class.getName())) {
839-
getOrCreateConstant(getId(line));
840-
}
868+
private void loadAllAnalysisElements(String encoding) {
869+
encoding.lines().forEach(this::loadEncodedGraphLineAnalysisElements);
870+
}
871+
872+
protected void loadEncodedGraphLineAnalysisElements(String line) {
873+
if (line.contains(PointsToAnalysisType.class.getName())) {
874+
getAnalysisType(getId(line));
875+
} else if (line.contains(PointsToAnalysisMethod.class.getName())) {
876+
getAnalysisMethod(getId(line));
877+
} else if (line.contains(PointsToAnalysisField.class.getName())) {
878+
getAnalysisField(getId(line));
879+
} else if (line.contains(ImageHeapInstance.class.getName()) || line.contains(ImageHeapObjectArray.class.getName()) || line.contains(ImageHeapPrimitiveArray.class.getName())) {
880+
getOrCreateConstant(getId(line));
841881
}
842882
}
843883

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858

5959
public class ImageLayerSnapshotUtil {
6060
public static final String FILE_NAME_PREFIX = "layer-snapshot-";
61+
public static final String GRAPHS_FILE_NAME_PREFIX = "layer-snapshot-graphs-";
6162
public static final String FILE_EXTENSION = ".json";
6263

6364
public static final String CONSTRUCTOR_NAME = "<init>";
@@ -196,6 +197,10 @@ public static String snapshotFileName(String imageName) {
196197
return FILE_NAME_PREFIX + imageName + FILE_EXTENSION;
197198
}
198199

200+
public static String snapshotGraphsFileName(String imageName) {
201+
return GRAPHS_FILE_NAME_PREFIX + imageName + FILE_EXTENSION;
202+
}
203+
199204
public String getTypeIdentifier(AnalysisType type) {
200205
String javaName = type.toJavaName(true);
201206
return addModuleName(javaName, type.getJavaClass().getModule().getName());

0 commit comments

Comments
 (0)