Skip to content

Commit d7571e0

Browse files
committed
Add reporting for number and size of included resources. Throw
explanatory error message when the image heap gets too large (2GB is the current limit).
1 parent 3fa330a commit d7571e0

File tree

5 files changed

+31
-22
lines changed

5 files changed

+31
-22
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848

4949
import org.graalvm.collections.EconomicMap;
5050
import org.graalvm.collections.MapCursor;
51+
import org.graalvm.collections.UnmodifiableEconomicMap;
5152
import org.graalvm.nativeimage.ImageInfo;
5253
import org.graalvm.nativeimage.ImageSingletons;
5354
import org.graalvm.nativeimage.Platform;
@@ -275,23 +276,8 @@ public void forEachResource(BiConsumer<ModuleResourceKey, ConditionalRuntimeValu
275276
}
276277

277278
@Platforms(Platform.HOSTED_ONLY.class)
278-
public ConditionalRuntimeValue<ResourceStorageEntryBase> getResource(ModuleResourceKey storageKey) {
279-
return resources.get(storageKey);
280-
}
281-
282-
@Platforms(Platform.HOSTED_ONLY.class)
283-
public Iterable<ConditionalRuntimeValue<ResourceStorageEntryBase>> resources() {
284-
return resources.getValues();
285-
}
286-
287-
@Platforms(Platform.HOSTED_ONLY.class)
288-
public Iterable<ModuleResourceKey> resourceKeys() {
289-
return resources.getKeys();
290-
}
291-
292-
@Platforms(Platform.HOSTED_ONLY.class)
293-
public int count() {
294-
return resources.size();
279+
public UnmodifiableEconomicMap<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> resources() {
280+
return resources;
295281
}
296282

297283
public static long getLastModifiedTime() {
@@ -828,7 +814,7 @@ public void afterCompilation(AfterCompilationAccess access) {
828814
* of lazily initialized fields. Only the byte[] arrays themselves can be safely made
829815
* read-only.
830816
*/
831-
for (ConditionalRuntimeValue<ResourceStorageEntryBase> entry : Resources.currentLayer().resources()) {
817+
for (ConditionalRuntimeValue<ResourceStorageEntryBase> entry : Resources.currentLayer().resources().getValues()) {
832818
var unconditionalEntry = entry.getValueUnconditionally();
833819
if (unconditionalEntry.hasData()) {
834820
for (byte[] resource : unconditionalEntry.getData()) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HeapBreakdownProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ protected void calculate(BeforeImageWriteAccessImpl access, boolean resourcesAre
168168
if (!ImageLayerBuildingSupport.buildingExtensionLayer() && resourcesAreReachable) {
169169
/* Extract byte[] for resources. */
170170
int resourcesByteArrayCount = 0;
171-
for (ConditionalRuntimeValue<ResourceStorageEntryBase> resourceList : Resources.currentLayer().resources()) {
171+
for (ConditionalRuntimeValue<ResourceStorageEntryBase> resourceList : Resources.currentLayer().resources().getValues()) {
172172
if (resourceList.getValueUnconditionally().hasData()) {
173173
for (byte[] resource : resourceList.getValueUnconditionally().getData()) {
174174
resourcesByteArraySize += objectLayout.getArraySize(JavaKind.Byte, resource.length, true);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
import java.util.stream.Collectors;
5353
import java.util.stream.Stream;
5454

55+
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
56+
import com.oracle.svm.core.jdk.resources.ResourceStorageEntryBase;
5557
import org.graalvm.nativeimage.ImageSingletons;
5658
import org.graalvm.nativeimage.hosted.Feature;
5759
import org.graalvm.nativeimage.impl.ImageSingletonsSupport;
@@ -109,6 +111,7 @@
109111
import jdk.graal.compiler.options.OptionStability;
110112
import jdk.graal.compiler.options.OptionValues;
111113
import jdk.graal.compiler.util.json.JsonWriter;
114+
import org.graalvm.nativeimage.impl.RuntimeResourceSupport;
112115

113116
@SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class, layeredInstallationKind = Independent.class)
114117
public class ProgressReporter {
@@ -506,10 +509,24 @@ private void printAnalysisStatistics(AnalysisUniverse universe, Collection<Strin
506509
String stubsFormat = "%,9d downcalls and %,d upcalls ";
507510
recordJsonMetric(AnalysisResults.FOREIGN_DOWNCALLS, (numForeignDowncalls >= 0 ? numForeignDowncalls : UNAVAILABLE_METRIC));
508511
recordJsonMetric(AnalysisResults.FOREIGN_UPCALLS, (numForeignUpcalls >= 0 ? numForeignUpcalls : UNAVAILABLE_METRIC));
509-
if (numForeignDowncalls >= 0 || numForeignUpcalls >= 0) {
512+
if (numForeignDowncalls > 0 || numForeignUpcalls > 0) {
510513
l().a(stubsFormat, numForeignDowncalls, numForeignUpcalls)
511514
.doclink("registered for foreign access", "#glossary-foreign-downcall-and-upcall-registrations").println();
512515
}
516+
RuntimeResourceSupport runtimeResourceSupport = ImageSingletons.lookup(RuntimeResourceSupport.class);
517+
int resourceCount = Resources.currentLayer().resources().size();
518+
long totalResourceSize = 0;
519+
for (ConditionalRuntimeValue<ResourceStorageEntryBase> value : Resources.currentLayer().resources().getValues()) {
520+
if (value.getValueUnconditionally().hasData()) {
521+
for (byte[] bytes : value.getValueUnconditionally().getData()) {
522+
totalResourceSize += bytes.length;
523+
}
524+
}
525+
}
526+
if (resourceCount > 0) {
527+
l().a("%,9d %s found with %s total size", resourceCount, resourceCount == 1 ? "resource" : "resources", ByteFormattingUtil.bytesToHuman(totalResourceSize)).println();
528+
}
529+
ConditionalRuntimeValue<ResourceStorageEntryBase> value;
513530
int numLibraries = libraries.size();
514531
if (numLibraries > 0) {
515532
TreeSet<String> sortedLibraries = new TreeSet<>(libraries);
@@ -578,7 +595,7 @@ public void printCreationEnd(int imageFileSize, int heapObjectCount, long imageH
578595
String format = "%9s (%5.2f%%) for ";
579596
l().a(format, ByteFormattingUtil.bytesToHuman(codeAreaSize), Utils.toPercentage(codeAreaSize, imageFileSize))
580597
.doclink("code area", "#glossary-code-area").a(":%,10d compilation units", numCompilations).println();
581-
int numResources = Resources.currentLayer().count();
598+
int numResources = Resources.currentLayer().resources().size();
582599
recordJsonMetric(ImageDetailKey.IMAGE_HEAP_RESOURCE_COUNT, numResources);
583600
l().a(format, ByteFormattingUtil.bytesToHuman(imageHeapSize), Utils.toPercentage(imageHeapSize, imageFileSize))
584601
.doclink("image heap", "#glossary-image-heap").a(":%,9d objects and %,d resources", heapObjectCount, numResources).println();

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public void addGlob(ConfigurationCondition condition, String module, String glob
200200

201201
@Override
202202
public void addCondition(ConfigurationCondition condition, Module module, String resourcePath) {
203-
var conditionalResource = Resources.currentLayer().getResource(createStorageKey(module, resourcePath));
203+
var conditionalResource = Resources.currentLayer().resources().get(createStorageKey(module, resourcePath));
204204
if (conditionalResource != null) {
205205
classInitializationSupport.addForTypeReachedTracking(condition.getType());
206206
conditionalResource.getConditions().addCondition(condition);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import java.util.Set;
5151
import java.util.stream.Collectors;
5252

53+
import com.oracle.svm.hosted.ByteFormattingUtil;
5354
import org.graalvm.collections.Pair;
5455
import org.graalvm.nativeimage.ImageSingletons;
5556
import org.graalvm.nativeimage.c.CHeader;
@@ -503,6 +504,11 @@ public void build(String imageName, DebugContext debug) {
503504
*/
504505
boolean padImageHeap = !SpawnIsolates.getValue() || MremapImageHeap.getValue();
505506
long paddedImageHeapSize = padImageHeap ? NumUtil.roundUp(imageHeapSize, alignment) : imageHeapSize;
507+
508+
VMError.guarantee(NumUtil.isInt(paddedImageHeapSize),
509+
"The size of the image heap is %s and therefore too large. It must be smaller than %s. This can happen when very large resource files are included in the image or a build time initialized class creates a large cache.",
510+
ByteFormattingUtil.bytesToHuman(paddedImageHeapSize),
511+
ByteFormattingUtil.bytesToHuman(Integer.MAX_VALUE));
506512
RelocatableBuffer heapSectionBuffer = new RelocatableBuffer(paddedImageHeapSize, objectFile.getByteOrder());
507513
ProgbitsSectionImpl heapSectionImpl = new BasicProgbitsSectionImpl(heapSectionBuffer.getBackingArray());
508514
// Note: On isolate startup the read only part of the heap will be set up as such.

0 commit comments

Comments
 (0)