Skip to content

Commit e5c3cac

Browse files
committed
[GR-43385] Group by modules and JARs in code area breakdown.
PullRequest: graal/13478
2 parents 4c119fd + 0b52fa9 commit e5c3cac

File tree

2 files changed

+85
-46
lines changed

2 files changed

+85
-46
lines changed

docs/reference-manual/native-image/BuildOutput.md

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,50 @@ Below is the example output when building a native executable of the `HelloWorld
2020
================================================================================
2121
GraalVM Native Image: Generating 'helloworld' (executable)...
2222
================================================================================
23-
[1/8] Initializing... (2.5s @ 0.21GB)
24-
Version info: 'GraalVM dev Java 11 CE'
25-
C compiler: gcc (linux, x86_64, 9.3.0)
23+
[1/8] Initializing... (3.3s @ 0.25GB)
24+
Version info: 'GraalVM dev Java 19+36-jvmci-23.0-b01 CE'
25+
Java version info: '19+36-jvmci-23.0-b01'
26+
C compiler: gcc (linux, x86_64, 11.3.0)
2627
Garbage collector: Serial GC (max heap size: unlimited)
27-
[2/8] Performing analysis... [*******] (5.6s @ 0.46GB)
28-
2,718 (72.93%) of 3,727 types reachable
29-
3,442 (53.43%) of 6,442 fields reachable
30-
12,128 (44.82%) of 27,058 methods reachable
31-
27 types, 0 fields, and 271 methods registered for reflection
32-
58 types, 59 fields, and 52 methods registered for JNI access
28+
[2/8] Performing analysis... [****] (6.2s @ 0.47GB)
29+
2,880 (71.50%) of 4,028 types reachable
30+
3,519 (51.06%) of 6,892 fields reachable
31+
13,339 (45.11%) of 29,570 methods reachable
32+
879 types, 0 fields, and 356 methods registered for reflection
33+
57 types, 56 fields, and 52 methods registered for JNI access
3334
4 native libraries: dl, pthread, rt, z
34-
[3/8] Building universe... (0.5s @ 0.61GB)
35-
[4/8] Parsing methods... [*] (0.5s @ 0.86GB)
36-
[5/8] Inlining methods... [****] (0.5s @ 0.73GB)
37-
[6/8] Compiling methods... [**] (3.7s @ 2.38GB)
38-
[7/8] Layouting methods... [*] (0.5s @ 0.71GB)
39-
[8/8] Creating image... (2.1s @ 1.04GB)
40-
4.00MB (28.31%) for code area: 7,073 compilation units
41-
5.90MB (41.70%) for image heap: 83,319 objects and 5 resources
42-
3.24MB (22.91%) for debug info generated in 1.0s
43-
1.00MB ( 7.08%) for other data
44-
14.15MB in total
35+
[3/8] Building universe... (1.1s @ 2.26GB)
36+
[4/8] Parsing methods... [*] (1.0s @ 2.76GB)
37+
[5/8] Inlining methods... [***] (0.8s @ 0.99GB)
38+
[6/8] Compiling methods... [***] (6.4s @ 4.86GB)
39+
[7/8] Layouting methods... [**] (4.2s @ 3.98GB)
40+
[8/8] Creating image... (4.0s @ 2.04GB)
41+
4.52MB (22.97%) for code area: 7,470 compilation units
42+
7.06MB (35.87%) for image heap: 101,764 objects and 5 resources
43+
7.52MB (38.24%) for debug info generated in 1.8s
44+
590.19KB ( 2.93%) for other data
45+
19.68MB in total
4546
--------------------------------------------------------------------------------
46-
Top 10 packages in code area: Top 10 object types in image heap:
47-
632.68KB java.util 871.62KB byte[] for code metadata
48-
324.42KB java.lang 798.53KB java.lang.String
49-
223.90KB java.util.regex 774.91KB byte[] for general heap data
50-
221.62KB java.text 614.06KB java.lang.Class
51-
198.30KB com.oracle.svm.jni 492.51KB byte[] for java.lang.String
52-
166.02KB java.util.concurrent 314.81KB java.util.HashMap$Node
53-
115.44KB java.math 233.58KB c.o.s.c.h.DynamicHubCompanion
54-
98.48KB sun.text.normalizer 154.84KB java.lang.String[]
55-
97.42KB java.util.logging 139.54KB byte[] for embedded resources
56-
95.18KB c.oracle.svm.core.genscavenge 139.04KB char[]
57-
1.83MB for 118 more packages 1.29MB for 753 more object types
47+
Top 10 origins of code area: Top 10 object types in image heap:
48+
3.43MB java.base 1.01MB byte[] for code metadata
49+
760.98KB svm.jar (Native Image) 1000.72KB java.lang.String
50+
102.06KB java.logging 884.18KB byte[] for general heap data
51+
48.03KB org.graalvm.nativeimage.base 686.91KB byte[] for java.lang.String
52+
40.49KB jdk.proxy1 659.87KB java.lang.Class
53+
38.23KB jdk.proxy3 247.50KB c.o.s.c.h.DynamicHubCompanion
54+
25.73KB jdk.internal.vm.ci 239.25KB java.lang.Object[]
55+
23.55KB org.graalvm.sdk 226.08KB java.util.HashMap$Node
56+
11.10KB jdk.proxy2 173.15KB java.lang.String[]
57+
8.10KB jdk.internal.vm.compiler 163.22KB j.u.c.ConcurrentHashMap$Node
58+
1.39KB for 2 more origins 1.70MB for 808 more object types
5859
--------------------------------------------------------------------------------
59-
0.9s (5.6% of total time) in 17 GCs | Peak RSS: 3.22GB | CPU load: 10.87
60+
0.5s (1.8% of total time) in 24 GCs | Peak RSS: 5.62GB | CPU load: 8.92
6061
--------------------------------------------------------------------------------
6162
Produced artifacts:
62-
/home/janedoe/helloworld/helloworld (executable)
63+
/home/janedoe/helloworld/helloworld (executable, debug_info)
6364
/home/janedoe/helloworld/sources (debug_info)
64-
/home/janedoe/helloworld/helloworld (debug_info)
65-
/home/janedoe/helloworld/helloworld.build_artifacts.txt
6665
================================================================================
67-
Finished generating 'helloworld' in 16.2s.
66+
Finished generating 'helloworld' in 27.4s.
6867
```
6968
7069
## Build Stages
@@ -154,6 +153,14 @@ Debug info is also generated as part of this stage (if requested).
154153
The code area contains machine code produced by the Graal compiler for all reachable methods.
155154
Therefore, reducing the number of [reachable methods](#glossary-reachability) also reduces the size of the code area.
156155
156+
##### <a name="glossary-code-area-origins"></a>Origins of Code Area
157+
To help users understand where the machine code of the code area comes from, the build output shows a breakdown of the top origins.
158+
An origin is a group of Java sources and can be a JAR file, a package name, or a class name, depending on the information available.
159+
The [`java.base` module](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/module-summary.html), for example, contains base classes from the JDK.
160+
The `svm.jar` file, the `org.graalvm.nativeimage.base` module, and similar origins contain internal sources for the Native Image runtime.
161+
To reduce the size of the code area and with that, the total size of the native executable, re-evaluate the dependencies of your application based on the code area breakdown.
162+
Some libraries and frameworks are better prepared for Native Image than others, and newer versions of a library or framework may improve (or worsen) their code footprint.
163+
157164
#### <a name="glossary-image-heap"></a>Image Heap
158165
The heap contains reachable objects such as static application data, metadata, and `byte[]` for different purposes (see below).
159166

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

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.lang.management.OperatingSystemMXBean;
3434
import java.lang.reflect.Field;
3535
import java.nio.file.Path;
36+
import java.security.CodeSource;
3637
import java.util.ArrayList;
3738
import java.util.Collection;
3839
import java.util.Comparator;
@@ -95,6 +96,7 @@
9596
import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind;
9697
import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo;
9798
import com.oracle.svm.hosted.meta.HostedMetaAccess;
99+
import com.oracle.svm.hosted.meta.HostedMethod;
98100
import com.oracle.svm.hosted.reflect.ReflectionHostedSupport;
99101
import com.oracle.svm.hosted.util.VMErrorReporter;
100102
import com.oracle.svm.util.ImageBuildStatistics;
@@ -109,8 +111,6 @@ public class ProgressReporter {
109111
private static final boolean IS_CI = System.console() == null || System.getenv("CI") != null;
110112
private static final boolean IS_DUMB_TERM = isDumbTerm();
111113
private static final int MAX_NUM_BREAKDOWN = 10;
112-
private static final String CODE_BREAKDOWN_TITLE = String.format("Top %d packages in code area:", MAX_NUM_BREAKDOWN);
113-
private static final String HEAP_BREAKDOWN_TITLE = String.format("Top %d object types in image heap:", MAX_NUM_BREAKDOWN);
114114
private static final String STAGE_DOCS_URL = "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/BuildOutput.md";
115115
private static final double EXCESSIVE_GC_MIN_THRESHOLD_MILLIS = 15_000;
116116
private static final double EXCESSIVE_GC_RATIO = 0.5;
@@ -490,15 +490,45 @@ public void createBreakdowns(HostedMetaAccess metaAccess, Collection<CompileTask
490490

491491
private void calculateCodeBreakdown(Collection<CompileTask> compilationTasks) {
492492
for (CompileTask task : compilationTasks) {
493-
String classOrPackageName = task.method.format("%H");
494-
int lastDotIndex = classOrPackageName.lastIndexOf('.');
495-
if (lastDotIndex > 0) {
496-
classOrPackageName = classOrPackageName.substring(0, lastDotIndex);
493+
String key = null;
494+
Class<?> javaClass = task.method.getDeclaringClass().getJavaClass();
495+
Module module = javaClass.getModule();
496+
if (module.isNamed()) {
497+
key = module.getName();
498+
if ("org.graalvm.nativeimage.builder".equals(key)) {
499+
key = "svm.jar (Native Image)";
500+
}
501+
} else {
502+
key = findJARFile(javaClass);
503+
if (key == null) {
504+
key = findPackageOrClassName(task.method);
505+
}
497506
}
498-
codeBreakdown.merge(classOrPackageName, (long) task.result.getTargetCodeSize(), Long::sum);
507+
codeBreakdown.merge(key, (long) task.result.getTargetCodeSize(), Long::sum);
499508
}
500509
}
501510

511+
private static String findJARFile(Class<?> javaClass) {
512+
CodeSource codeSource = javaClass.getProtectionDomain().getCodeSource();
513+
if (codeSource != null && codeSource.getLocation() != null) {
514+
String path = codeSource.getLocation().getPath();
515+
if (path.endsWith(".jar")) {
516+
// Use String API to determine basename of path to handle both / and \.
517+
return path.substring(Math.max(path.lastIndexOf('/') + 1, path.lastIndexOf('\\') + 1));
518+
}
519+
}
520+
return null;
521+
}
522+
523+
private static String findPackageOrClassName(HostedMethod method) {
524+
String qualifier = method.format("%H");
525+
int lastDotIndex = qualifier.lastIndexOf('.');
526+
if (lastDotIndex > 0) {
527+
qualifier = qualifier.substring(0, lastDotIndex);
528+
}
529+
return qualifier;
530+
}
531+
502532
private void calculateHeapBreakdown(HostedMetaAccess metaAccess, Collection<ObjectInfo> heapObjects) {
503533
long stringByteLength = 0;
504534
for (ObjectInfo o : heapObjects) {
@@ -558,7 +588,9 @@ private void printBreakdowns() {
558588
.sorted(Entry.comparingByValue(Comparator.reverseOrder())).iterator();
559589

560590
final TwoColumnPrinter p = new TwoColumnPrinter();
561-
p.l().yellowBold().a(CODE_BREAKDOWN_TITLE).jumpToMiddle().a(HEAP_BREAKDOWN_TITLE).reset().flushln();
591+
p.l().yellowBold().a(String.format("Top %d ", MAX_NUM_BREAKDOWN)).doclink("origins", "#glossary-code-area-origins").a(" of code area:")
592+
.jumpToMiddle()
593+
.a(String.format("Top %d object types in image heap:", MAX_NUM_BREAKDOWN)).reset().flushln();
562594

563595
long printedCodeBytes = 0;
564596
long printedHeapBytes = 0;
@@ -596,7 +628,7 @@ private void printBreakdowns() {
596628
int numHeapItems = heapBreakdown.size();
597629
long totalCodeBytes = codeBreakdown.values().stream().collect(Collectors.summingLong(Long::longValue));
598630
long totalHeapBytes = heapBreakdown.values().stream().collect(Collectors.summingLong(Long::longValue));
599-
p.l().a(String.format("%9s for %s more packages", Utils.bytesToHuman(totalCodeBytes - printedCodeBytes), numCodeItems - printedCodeItems))
631+
p.l().a(String.format("%9s for %s more ", Utils.bytesToHuman(totalCodeBytes - printedCodeBytes), numCodeItems - printedCodeItems)).doclink("origins", "#glossary-code-area-origins")
600632
.jumpToMiddle()
601633
.a(String.format("%9s for %s more object types", Utils.bytesToHuman(totalHeapBytes - printedHeapBytes), numHeapItems - printedHeapItems)).flushln();
602634
}

0 commit comments

Comments
 (0)