Skip to content

[GR-58088] Improve layer build times and memory usage. #9681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,7 @@ private Object decode(String encoded) {
deferred = new ArrayList<>();
lineNum = 0;

List<String> lines = encoded.lines().toList();
Iterator<String> iter = lines.iterator();
Iterator<String> iter = encoded.lines().iterator();
try {
while (iter.hasNext()) {
String line = iter.next();
Expand Down Expand Up @@ -707,7 +706,8 @@ private Object decode(String encoded) {
d.runnable().run();
}
} catch (Throwable e) {
throw new GraalError(e, "Error on line %d: %s", lineNum, lines.get(lineNum - 1));
String line = encoded.lines().skip(lineNum - 1).findFirst().get();
throw new GraalError(e, "Error on line %d: %s", lineNum, line);
} finally {
deferred = null;
lineNum = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -64,13 +65,18 @@ public final class JsonParser {
private final Reader source;

// Current reading position within source
private int pos = 0;
private int pos;
// Current line number, used for error reporting.
private int line = 0;
// Position of the start of the current line in source, used for error reporting.
private int beginningOfLine = 0;
// Next character to be scanned, obtained from source
private int next;
/**
* Characters following 'next'. Managing our own buffer instead of using {@link BufferedReader}
* avoids unnecessary locking that becomes significant when getting individual characters.
*/
private final CharBuffer buffer = CharBuffer.allocate(8192).limit(0);

private static final int EOF = -1;

Expand All @@ -90,12 +96,12 @@ public JsonParser(String source) throws IOException {
/**
* Creates a new {@link JsonParser} that reads characters from {@code source}.
*
* @param source character stream containing JSON text. Will be adapted internally through a
* {@link BufferedReader}.
* @param source character reader containing JSON text.
*/
public JsonParser(Reader source) throws IOException {
this.source = new BufferedReader(source);
next = source.read();
this.source = source;
next();
this.pos = 0;
}

/**
Expand Down Expand Up @@ -475,8 +481,10 @@ private Number parseNumber() throws IOException {
}

private Object parseKeyword(final String keyword, final Object value) throws IOException {
if (!read(keyword.length()).equals(keyword)) {
throw expectedError(pos, "json literal", "ident");
for (int i = 0; i < keyword.length(); i++) {
if (next() != keyword.charAt(i)) {
throw expectedError(pos, "json literal", "ident");
}
}
return value;
}
Expand All @@ -487,22 +495,19 @@ private int peek() {

private int next() throws IOException {
int cur = next;
next = source.read();
if (buffer.isEmpty()) {
buffer.clear(); // resets position and limit
if (source.read(buffer) == -1) { // eof
next = -1;
return cur;
}
buffer.flip();
}
next = buffer.get();
pos++;
return cur;
}

private String read(int length) throws IOException {
char[] buffer = new char[length];

buffer[0] = (char) peek();
source.read(buffer, 1, length - 1);
pos += length - 1;
next();

return String.valueOf(buffer);
}

private void skipWhiteSpace() throws IOException {
while (next != -1) {
switch (peek()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ public void cleanupAfterAnalysis() {

universe.getHeapScanner().cleanupAfterAnalysis();
universe.getHeapVerifier().cleanupAfterAnalysis();
if (universe.getImageLayerLoader() != null) {
universe.getImageLayerLoader().cleanupAfterAnalysis();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -135,6 +137,7 @@
import com.oracle.graal.pointsto.util.AnalysisFuture;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.core.common.SuppressFBWarnings;
import jdk.graal.compiler.debug.GraalError;
import jdk.graal.compiler.nodes.EncodedGraph;
Expand Down Expand Up @@ -302,7 +305,7 @@ public class ImageLayerLoader {
protected final Map<Integer, AnalysisMethod> methods = new ConcurrentHashMap<>();
protected final Map<Integer, AnalysisField> fields = new ConcurrentHashMap<>();
protected final Map<Integer, ImageHeapConstant> constants = new ConcurrentHashMap<>();
private final List<Path> loadPaths;
private final List<FilePaths> loadPaths;
private final Map<Integer, BaseLayerType> baseLayerTypes = new ConcurrentHashMap<>();
private final Map<Integer, Integer> typeToHubIdentityHashCode = new ConcurrentHashMap<>();
private final Map<Integer, BaseLayerMethod> baseLayerMethods = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -332,22 +335,22 @@ record FieldIdentifier(String tid, String name) {
protected HostedValuesProvider hostedValuesProvider;

protected EconomicMap<String, Object> jsonMap;
protected FileChannel graphsChannel;

private long imageHeapSize;

public record FilePaths(Path snapshot, Path snapshotGraphs) {
}

public ImageLayerLoader() {
this(new ImageLayerSnapshotUtil(), List.of());
}

public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List<Path> loadPaths) {
public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List<FilePaths> loadPaths) {
this.imageLayerSnapshotUtil = imageLayerSnapshotUtil;
this.loadPaths = loadPaths;
}

public List<Path> getLoadPaths() {
return loadPaths;
}

public AnalysisUniverse getUniverse() {
return universe;
}
Expand All @@ -360,16 +363,18 @@ public void setImageLayerLoaderHelper(ImageLayerLoaderHelper imageLayerLoaderHel
this.imageLayerLoaderHelper = imageLayerLoaderHelper;
}

/**
* Note this code is not thread safe.
*/
protected void loadJsonMap() {
/** This code is not thread safe. */
protected void openFilesAndLoadJsonMap() {
assert loadPaths.size() == 1 : "Currently only one path is supported for image layer loading " + loadPaths;
if (jsonMap == null) {
for (Path layerPath : loadPaths) {
try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(layerPath.toFile()))) {
Object json = new JsonParser(inputStreamReader).parse();
jsonMap = cast(json);
for (FilePaths paths : loadPaths) {
try {
graphsChannel = FileChannel.open(paths.snapshotGraphs);

try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(paths.snapshot.toFile()))) {
Object json = new JsonParser(inputStreamReader).parse();
jsonMap = cast(json);
}
} catch (IOException e) {
throw AnalysisError.shouldNotReachHere("Error during image layer snapshot loading", e);
}
Expand All @@ -378,10 +383,20 @@ protected void loadJsonMap() {
}

public void loadLayerAnalysis() {
loadJsonMap();
openFilesAndLoadJsonMap();
loadLayerAnalysis0();
}

public void cleanupAfterAnalysis() {
if (graphsChannel != null) {
try {
graphsChannel.close();
} catch (IOException e) {
throw AnalysisError.shouldNotReachHere(e);
}
}
}

/**
* Initializes the {@link ImageLayerLoader}.
*/
Expand Down Expand Up @@ -792,7 +807,7 @@ public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) {

public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) {
EconomicMap<String, Object> methodData = getMethodData(analysisMethod);
String encodedAnalyzedGraph = get(methodData, ANALYSIS_PARSED_GRAPH_TAG);
String encodedAnalyzedGraph = readEncodedGraph(methodData, ANALYSIS_PARSED_GRAPH_TAG);
Boolean intrinsic = get(methodData, INTRINSIC_TAG);
/*
* Methods without a persisted graph are folded and static methods.
Expand All @@ -802,21 +817,44 @@ public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod)
if (encodedAnalyzedGraph != null) {
EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph);
if (hasStrengthenedGraph(analysisMethod)) {
loadAllAnalysisElements(get(methodData, STRENGTHENED_GRAPH_TAG));
loadAllAnalysisElements(readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG));
}
return new AnalysisParsedGraph(analyzedGraph, intrinsic);
}
throw AnalysisError.shouldNotReachHere("The method " + analysisMethod + " does not have a graph from the base layer");
}

private String readEncodedGraph(EconomicMap<String, Object> methodData, String elementIdentifier) {
String location = get(methodData, elementIdentifier);
int closingBracketAt = location.length() - 1;
AnalysisError.guarantee(location.charAt(0) == '@' && location.charAt(closingBracketAt) == ']', "Location must start with '@' and end with ']': %s", location);
int openingBracketAt = location.indexOf('[', 1, closingBracketAt);
AnalysisError.guarantee(openingBracketAt < closingBracketAt, "Location does not contain '[' at expected location: %s", location);
long offset;
long nbytes;
try {
offset = Long.parseUnsignedLong(location.substring(1, openingBracketAt));
nbytes = Long.parseUnsignedLong(location.substring(openingBracketAt + 1, closingBracketAt));
} catch (NumberFormatException e) {
throw AnalysisError.shouldNotReachHere("Location contains invalid positive integer(s): " + location);
}
ByteBuffer bb = ByteBuffer.allocate(NumUtil.safeToInt(nbytes));
try {
graphsChannel.read(bb, offset);
} catch (IOException e) {
throw AnalysisError.shouldNotReachHere("Failed reading a graph from location: " + location, e);
}
return new String(bb.array(), ImageLayerWriter.GRAPHS_CHARSET);
}

public boolean hasStrengthenedGraph(AnalysisMethod analysisMethod) {
EconomicMap<String, Object> methodData = getMethodData(analysisMethod);
return get(methodData, STRENGTHENED_GRAPH_TAG) != null;
}

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

}

protected void loadAllAnalysisElements(String encoding) {
for (String line : encoding.lines().toList()) {
if (line.contains(PointsToAnalysisType.class.getName())) {
getAnalysisType(getId(line));
} else if (line.contains(PointsToAnalysisMethod.class.getName())) {
getAnalysisMethod(getId(line));
} else if (line.contains(PointsToAnalysisField.class.getName())) {
getAnalysisField(getId(line));
} else if (line.contains(ImageHeapInstance.class.getName()) || line.contains(ImageHeapObjectArray.class.getName()) || line.contains(ImageHeapPrimitiveArray.class.getName())) {
getOrCreateConstant(getId(line));
}
private void loadAllAnalysisElements(String encoding) {
encoding.lines().forEach(this::loadEncodedGraphLineAnalysisElements);
}

protected void loadEncodedGraphLineAnalysisElements(String line) {
if (line.contains(PointsToAnalysisType.class.getName())) {
getAnalysisType(getId(line));
} else if (line.contains(PointsToAnalysisMethod.class.getName())) {
getAnalysisMethod(getId(line));
} else if (line.contains(PointsToAnalysisField.class.getName())) {
getAnalysisField(getId(line));
} else if (line.contains(ImageHeapInstance.class.getName()) || line.contains(ImageHeapObjectArray.class.getName()) || line.contains(ImageHeapPrimitiveArray.class.getName())) {
getOrCreateConstant(getId(line));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@

public class ImageLayerSnapshotUtil {
public static final String FILE_NAME_PREFIX = "layer-snapshot-";
public static final String GRAPHS_FILE_NAME_PREFIX = "layer-snapshot-graphs-";
public static final String FILE_EXTENSION = ".json";

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

public static String snapshotGraphsFileName(String imageName) {
return GRAPHS_FILE_NAME_PREFIX + imageName + FILE_EXTENSION;
}

public String getTypeIdentifier(AnalysisType type) {
String javaName = type.toJavaName(true);
return addModuleName(javaName, type.getJavaClass().getModule().getName());
Expand Down
Loading