Skip to content
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

[GR-52170] Document -O, -march, and build artifacts. #8424

Closed
wants to merge 4 commits into from
Closed
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
15 changes: 13 additions & 2 deletions docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Recommendations:
--------------------------------------------------------------------------------
0.8s (4.6% of total time) in 35 GCs | Peak RSS: 1.93GB | CPU load: 9.61
--------------------------------------------------------------------------------
Produced artifacts:
Build artifacts:
/home/janedoe/helloworld/helloworld (executable)
/home/janedoe/helloworld/helloworld.debug (debug_info)
/home/janedoe/helloworld/sources (debug_info)
Expand Down Expand Up @@ -341,11 +341,22 @@ If there is enough headroom and the [GC statistics](#glossary-garbage-collection
The CPU time used by the process divided by the total process time.
Increase the number of CPU cores to reduce the time to build the native binary.

## <a name="glossary-build-artifacts"></a>Build Artifacts

The list of all build artifacts.
This includes the generated native binary, but it can also contain other artifacts such as additional libraries, C header files, or debug info.
Some of these artifacts must remain in the same location with the native binary as they are needed at run time.
For applications using AWT, for example, the build process will also output libraries from the JDK and shims to provide compatible AWT support.
These libraries need to be copied and distributed together with the native binary.
Use the `-H:+GenerateBuildArtifactsFile` option to instruct the builder to produce a machine-readable version of the build artifact list in JSON format.
Such a JSON file validates against the JSON schema defined in [`build-artifacts-schema-v0.9.0.json`](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/build-artifacts-schema-v0.9.0.json).
This schema also contains descriptions for each possible artifact type and explains whether they are needed at run time or not.

## Machine-Readable Build Output

The build output produced by the `native-image` builder is designed for humans, can evolve with new releases, and should thus not be parsed in any way by tools.
Instead, use the `-H:BuildOutputJSONFile=<file.json>` option to instruct the builder to produce machine-readable build output in JSON format that can be used, for example, for building monitoring tools.
The JSON files validate against the JSON schema defined in [`build-output-schema-v0.9.2.json`](https://github.com/oracle/graal/tree/master/docs/reference-manual/native-image/assets/build-output-schema-v0.9.2.json).
Such a JSON file validates against the JSON schema defined in [`build-output-schema-v0.9.2.json`](https://github.com/oracle/graal/tree/master/docs/reference-manual/native-image/assets/build-output-schema-v0.9.2.json).
Note that a JSON file is produced if and only if a build succeeds.

The following example illustrates how this could be used in a CI/CD build pipeline to check that the number of reachable methods does not exceed a certain threshold:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference-manual/native-image/MemoryManagement.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ Here is a small subset of the options that can be specified when doing performan

```shell
# Build and execute a native image that uses the G1 GC with a region size of 2MB and a maximum pause time goal of 100ms
native-image --gc=G1 -H:G1RegionSize=2m -R:MaxGCPauseMillis=100 HelloWorld
native-image --gc=G1 -H:G1HeapRegionSize=2m -R:MaxGCPauseMillis=100 HelloWorld
./helloworld

# Execute the native image from above and override the maximum pause time goal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,35 @@ permalink: /reference-manual/native-image/optimizations-and-performance/

# Optimizations and Performance

Native Image provides advanced mechanisms to further optimize the generated binary:
Native Image provides different mechanisms that enable users to optimize a generated binary in terms of performance, file size, build time, debuggability, and other metrics.

### Optimization Levels

Similar to `gcc` and `clang`, users can control the optimization level using the `-O` option.
By default, `-O2` is used which aims for a good tradeoff between performance, file size, and build time.
The following table provides an overview of the different optimization levels and explains when they are useful:

| Level | Optimizations | Use Cases |
|:---:|:---:|---|
| `-Ob` | Reduced | Quick build mode: Speeds up builds during development by avoiding time-consuming optimizations. This can also reduce file size sometimes. |
| `-O0` | None | Typically used together with `-g` to improve the debugging experience. |
| `-O1` | Basic | Trades performance for reduced file size and build time. Oracle GraalVM's `-O1` is somewhat comparable to `-O2` in GraalVM Community Edition. |
| `-O2` | Advanced | **Default:** Aims for good performance at a reasonable file size. |
| `-O3` | All | Aims for the best performance at the cost of longer build times. Used automatically by Oracle GraalVM for [PGO builds](guides/optimize-native-executable-with-pgo.md) (`--pgo` option). `-O3` and `-O2` are identical in GraalVM Community Edition. |

### Optimizing for Specific Machines

Native Image provides a `-march` option that works similarly to the ones in `gcc` and `clang`: it enables users to control the set of instructions that the Graal compiler can use when compiling code to native.
By default, Native Image uses [`x86-64-v3` on x64](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels){:target="_blank"} and [`armv8-a` on AArch64](https://en.wikipedia.org/wiki/ARM_architecture_family#Cores){:target="_blank"}.
Use `-march=list` to list all available machine types.
If the generated binary is built on the same or similar machine type that it is also deployed on, use `-march=native`.
This option instructs the compiler to use all instructions that it finds available on the machine the binary is generated on.
If the generated binary, on the other hand, is distributed to users with many different, and potentially very old machines, use `-march=compatibility`.
This reduces the set of instructions used by the compiler to a minimum and thus improves the compatibility of the generated binary.

### Additional Features

Native Image provides additional features to further optimize a generated binary:

- Profile-Guided Optimizations (PGO) can provide additional performance gain and higher throughput for most native images. See [Optimize a Native Executable with PGO](guides/optimize-native-executable-with-pgo.md).
- Choosing an appropriate Garbage Collector and tailoring the garbage collection policy can reduce GC times. See [Memory Management](MemoryManagement.md).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Build information generated by Native Image (not needed at run-time)",
"title": "Build information generated by Native Image (not needed at run time)",
"type": "array"
},
"c_headers": {
Expand All @@ -21,7 +21,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "C header files generated by Native Image (not needed at run-time)",
"title": "C header files generated by Native Image (not needed at run time)",
"type": "array"
},
"debug_info": {
Expand All @@ -31,7 +31,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Debug information generated by Native Image (not needed at run-time)",
"title": "Debug information generated by Native Image (not needed at run time)",
"type": "array"
},
"executables": {
Expand All @@ -41,7 +41,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Executables generated by Native Image (needed at run-time)",
"title": "Executables generated by Native Image (needed at run time)",
"type": "array"
},
"import_libraries": {
Expand All @@ -51,7 +51,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Import libraries generated by Native Image (not needed at run-time)",
"title": "Import libraries generated by Native Image (not needed at run time)",
"type": "array"
},
"jdk_libraries": {
Expand All @@ -61,7 +61,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "JDK libraries copied by Native Image (needed at run-time)",
"title": "JDK libraries copied by Native Image (needed at run time)",
"type": "array"
},
"language_home": {
Expand All @@ -71,7 +71,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Language home artifacts for Truffle languages (needed at run-time)",
"title": "Language home artifacts for Truffle languages (needed at run time)",
"type": "array"
},
"shared_libraries": {
Expand All @@ -81,7 +81,7 @@
"title": "Relative path to file or directory",
"type": "string"
},
"title": "Shared libraries generated by Native Image (not needed at run-time)",
"title": "Shared libraries generated by Native Image (needed at run time)",
"type": "array"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ private void printArtifacts(Map<ArtifactType, List<Path>> artifacts) {
return;
}
l().printLineSeparator();
l().yellowBold().a("Produced artifacts:").reset().println();
l().yellowBold().doclink("Build artifacts", "#glossary-build-artifacts").a(":").reset().println();
// Use TreeMap to sort paths alphabetically.
Map<Path, List<String>> pathToTypes = new TreeMap<>();
artifacts.forEach((artifactType, paths) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,6 +26,7 @@

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.graalvm.nativeimage.Platform;

Expand Down Expand Up @@ -86,4 +87,8 @@ static String getSelectedOrDefaultMArch() {
return "unknown";
}
}

static List<String> toNames(CPUType[] values) {
return Arrays.stream(values).map(CPUType::getName).toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -133,7 +133,7 @@ public static EnumSet<CPUFeature> getCPUFeaturesForArch(String marchValue) {
throw UserError.abort("Unsupported architecture '%s'. Please adjust '%s'. On AArch64, only %s are available.",
marchValue,
SubstrateOptionsParser.commandArgument(NativeImageOptions.MicroArchitecture, marchValue),
StringUtil.joinSingleQuoted(values()));
StringUtil.joinSingleQuoted(CPUType.toNames(values())));
}
List<CPUFeature> features = new ArrayList<>(value.getFeatures());
processFeatureModifiers(features, archParts);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -177,7 +177,7 @@ public static EnumSet<CPUFeature> getCPUFeaturesForArch(String marchValue) {
throw UserError.abort("Unsupported architecture '%s'. Please adjust '%s'. On AMD64, only %s are available.",
marchValue,
SubstrateOptionsParser.commandArgument(NativeImageOptions.MicroArchitecture, marchValue),
StringUtil.joinSingleQuoted(values()));
StringUtil.joinSingleQuoted(CPUType.toNames(values())));
}
return value.getFeatures();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -91,7 +91,7 @@ private static CPUFeature[] getNativeOrEmpty() {
name = cpuTypeName;
parent = cpuTypeParentOrNull;
specificFeatures = features.length > 0 ? EnumSet.copyOf(List.of(features)) : EnumSet.noneOf(CPUFeature.class);
assert parent == null || parent.getFeatures().stream().noneMatch(f -> specificFeatures.contains(f)) : "duplicate features detected but not allowed";
assert parent == null || parent.getFeatures().stream().noneMatch(specificFeatures::contains) : "duplicate features detected but not allowed";
}

@Override
Expand All @@ -106,7 +106,7 @@ public CPUTypeRISCV64 getParent() {

@Override
public String getSpecificFeaturesString() {
return specificFeatures.stream().map(f -> f.name()).collect(Collectors.joining(" + "));
return specificFeatures.stream().map(Enum::name).collect(Collectors.joining(" + "));
}

public EnumSet<CPUFeature> getFeatures() {
Expand Down Expand Up @@ -136,7 +136,7 @@ public static EnumSet<CPUFeature> getCPUFeaturesForArch(String marchValue) {
throw UserError.abort("Unsupported architecture '%s'. Please adjust '%s'. On RISCV64, only %s are available.",
marchValue,
SubstrateOptionsParser.commandArgument(NativeImageOptions.MicroArchitecture, marchValue),
StringUtil.joinSingleQuoted(values()));
StringUtil.joinSingleQuoted(CPUType.toNames(values())));
}
return value.getFeatures();
}
Expand Down
Loading