Skip to content

Commit 421b6b6

Browse files
authored
Add support for PGO instrumentation (#471)
* Add support for PGO instrumentation This commit adds support for PGO instrumentation. This should be enabled by adding the `--pgo-instrument` option to the Gradle command line. When this is done, then the generated binary will be compiled with PGO instrumentation enabled, and the binary name will be suffixed with `-instrumented`. It is possible to run the instrumented binary directly too, in which case the profile files will be written in the same directory as the binary. * Add support for a PGO profiles directory By convention, the directory is set to `src/pgo-profiles/<binary>`. For example, for the `main` binary, the directory where to put PGO profiles would be `src/pgo-profiles/main`. If that directory is present _and that we're not instrumenting_, then the profile will be used when compiling with native image. It is possible to provide multiple profiles in a single directory. * Remove GraalVM version from workflows * Add documentation about PGO support See #457 * Fix JUnit native test * Make checkstyle happy * Fix tests * Temporarily(?) disable testing with config cache As we're not compatible. Test `org.graalvm.buildtools.gradle.OfficialMetadataRepoFunctionalTest` throws an incomprehensible error message, in all versions of Gradle I've tested: ``` Configuration cache state could not be cached: field `spec` of `org.gradle.api.internal.tasks.execution.SelfDescribingSpec` bean found in task `:compileJava` of type `org.gradle.api.tasks.compile.JavaCompile`: error writing value of type 'org.gradle.api.internal.tasks.compile.CompilerForkUtils$$Lambda$1235/0x00000008015b1c38' > Unable to make field private final java.lang.Object[] java.lang.invoke.SerializedLambda.capturedArgs accessible: module java.base does not "opens java.lang.invoke" to unnamed module @3cc98b0c ``` This PR also rewrote some code which fixed other configuration cache issues which arose _before_ reaching this one. * Upgrade to JUnit 5.10.0 * Make checkstyle happy * Fix test * Restore configuration cache tests * Update baseline versions for config cache
1 parent 7bdab7a commit 421b6b6

File tree

46 files changed

+338
-611
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+338
-611
lines changed

.github/actions/prepare-environment/action.yml

+3-7
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@ inputs:
66
description: 'secrets.GITHUB_TOKEN'
77
required: false
88
default: ''
9-
graalvm-version:
10-
description: 'GraalVM version to use'
11-
required: false
12-
default: 'dev'
139
java-version:
1410
description: 'Java version to use'
1511
required: false
16-
default: '11'
12+
default: '17'
1713
push-access:
1814
description: 'Does this workflow require push access?'
1915
required: false
@@ -26,13 +22,13 @@ inputs:
2622
runs:
2723
using: "composite"
2824
steps:
29-
- name: "🔧 Install GraalVM ${{ inputs.graalvm-version }} (JDK${{ inputs.java-version }})"
25+
- name: "🔧 Install GraalVM (JDK${{ inputs.java-version }})"
3026
uses: graalvm/setup-graalvm@main
3127
with:
3228
components: 'native-image'
3329
github-token: ${{ inputs.github-token }}
3430
java-version: ${{ inputs.java-version }}
35-
version: ${{ inputs.graalvm-version }}
31+
distribution: 'graalvm'
3632
- name: "🔒 Configure push access"
3733
if: ${{ inputs.push-access == '1' }}
3834
shell: "bash"

.github/workflows/deploy-documentation.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ jobs:
1818
strategy:
1919
fail-fast: false
2020
matrix:
21-
graalvm-version: [ latest ]
22-
java-version: [ 11 ]
21+
java-version: [ 17 ]
2322
os: [ ubuntu-20.04 ]
2423
steps:
2524
- name: "☁ Checkout repository"
@@ -30,7 +29,6 @@ jobs:
3029
uses: ./.github/actions/prepare-environment
3130
with:
3231
github-token: ${{ secrets.GITHUB_TOKEN }}
33-
graalvm-version: ${{ matrix.graalvm-version }}
3432
java-version: ${{ matrix.java-version }}
3533
push-access: 1
3634
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}

.github/workflows/deploy-snapshots.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ jobs:
2020
strategy:
2121
fail-fast: false
2222
matrix:
23-
graalvm-version: [ latest ]
24-
java-version: [ 11 ]
23+
java-version: [ 17 ]
2524
os: [ ubuntu-22.04 ]
2625
steps:
2726
- name: "☁ Checkout repository"
@@ -32,7 +31,6 @@ jobs:
3231
uses: ./.github/actions/prepare-environment
3332
with:
3433
github-token: ${{ secrets.GITHUB_TOKEN }}
35-
graalvm-version: ${{ matrix.graalvm-version }}
3634
java-version: ${{ matrix.java-version }}
3735
push-access: 1
3836
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}

.github/workflows/test-graalvm-metadata.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ jobs:
2424
strategy:
2525
fail-fast: false
2626
matrix:
27-
graalvm-version: [ 22.3.0 ]
28-
java-version: [ 11 ]
27+
java-version: [ 17 ]
2928
os: [ ubuntu-20.04 ]
3029
steps:
3130
- name: "☁️ Checkout repository"
3231
uses: actions/checkout@v2
3332
- name: "🔧 Prepare environment"
3433
uses: ./.github/actions/prepare-environment
3534
with:
36-
graalvm-version: ${{ matrix.graalvm-version }}
3735
java-version: ${{ matrix.java-version }}
3836
github-token: ${{ secrets.GITHUB_TOKEN }}
3937
- name: "❓ Checkstyle"

.github/workflows/test-junit-platform-native.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ jobs:
2424
strategy:
2525
fail-fast: false
2626
matrix:
27-
graalvm-version: [ 22.3.0 ]
28-
java-version: [ 11 ]
27+
java-version: [ 17 ]
2928
os: [ ubuntu-20.04 ]
3029
steps:
3130
- name: "☁️ Checkout repository"
3231
uses: actions/checkout@v2
3332
- name: "🔧 Prepare environment"
3433
uses: ./.github/actions/prepare-environment
3534
with:
36-
graalvm-version: ${{ matrix.graalvm-version }}
3735
java-version: ${{ matrix.java-version }}
3836
github-token: ${{ secrets.GITHUB_TOKEN }}
3937
- name: "❓ Checkstyle"

.github/workflows/test-native-gradle-plugin.yml

+4-10
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,14 @@ jobs:
2828
strategy:
2929
fail-fast: false
3030
matrix:
31-
graalvm-version: [ latest ] # dev
32-
java-version: [ 11 ]
31+
java-version: [ 17 ]
3332
os: [ ubuntu-20.04 ]
3433
steps:
3534
- name: "☁️ Checkout repository"
3635
uses: actions/checkout@v2
3736
- name: "🔧 Prepare environment"
3837
uses: ./.github/actions/prepare-environment
3938
with:
40-
graalvm-version: ${{ matrix.graalvm-version }}
4139
java-version: ${{ matrix.java-version }}
4240
github-token: ${{ secrets.GITHUB_TOKEN }}
4341
- name: "❓ Unit tests and inspections"
@@ -54,18 +52,16 @@ jobs:
5452
fail-fast: false
5553
matrix:
5654
gradle-version: ["current", "7.4"]
57-
gradle-config-cache-version: ["current", "7.5.1"]
55+
gradle-config-cache-version: ["current", "8.0.1"]
5856
# Following versions are disabled temporarily in order to speed up PR testing
5957
# "7.3.3", "7.2", "7.1", "6.8.3"
60-
graalvm-version: [ latest ] # dev
61-
java-version: [ 11 ]
58+
java-version: [ 17 ]
6259
os: [ ubuntu-20.04 ]
6360
steps:
6461
- name: "☁️ Checkout repository"
6562
uses: actions/checkout@v2
6663
- uses: ./.github/actions/prepare-environment
6764
with:
68-
graalvm-version: ${{ matrix.graalvm-version }}
6965
java-version: ${{ matrix.java-version }}
7066
github-token: ${{ secrets.GITHUB_TOKEN }}
7167
- name: "❓ Check and test the plugin"
@@ -86,15 +82,13 @@ jobs:
8682
strategy:
8783
fail-fast: false
8884
matrix:
89-
graalvm-version: [ latest ]
90-
java-version: [ 11 ]
85+
java-version: [ 17 ]
9186
os: [ windows-latest ]
9287
steps:
9388
- name: "☁️ Checkout repository"
9489
uses: actions/checkout@v2
9590
- uses: ./.github/actions/prepare-environment
9691
with:
97-
graalvm-version: ${{ matrix.graalvm-version }}
9892
java-version: ${{ matrix.java-version }}
9993
github-token: ${{ secrets.GITHUB_TOKEN }}
10094
- name: "❓ Check and test the Gradle plugin"

.github/workflows/test-native-maven-plugin.yml

+2-6
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,13 @@ jobs:
2828
strategy:
2929
fail-fast: false
3030
matrix:
31-
graalvm-version: [ latest ] # dev
32-
java-version: [ 11 ]
31+
java-version: [ 17 ]
3332
os: [ ubuntu-20.04 ]
3433
steps:
3534
- name: "☁️ Checkout repository"
3635
uses: actions/checkout@v2
3736
- uses: ./.github/actions/prepare-environment
3837
with:
39-
graalvm-version: ${{ matrix.graalvm-version }}
4038
java-version: ${{ matrix.java-version }}
4139
github-token: ${{ secrets.GITHUB_TOKEN }}
4240
- name: "❓ Check and test the plugin"
@@ -55,15 +53,13 @@ jobs:
5553
strategy:
5654
fail-fast: false
5755
matrix:
58-
graalvm-version: [ latest ] # dev
59-
java-version: [ 11 ]
56+
java-version: [ 17 ]
6057
os: [ windows-latest ]
6158
steps:
6259
- name: "☁️ Checkout repository"
6360
uses: actions/checkout@v2
6461
- uses: ./.github/actions/prepare-environment
6562
with:
66-
graalvm-version: ${{ matrix.graalvm-version }}
6763
java-version: ${{ matrix.java-version }}
6864
github-token: ${{ secrets.GITHUB_TOKEN }}
6965
- name: "❓ Check and test the Maven plugin"

build-logic/gradle-functional-testing/src/main/groovy/org.graalvm.build.functional-testing.gradle

+11-3
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ gradlePlugin.testSourceSets(sourceSets.functionalTest)
7575
configurations.functionalTestImplementation.extendsFrom(configurations.testImplementation)
7676

7777
def graalVm = javaToolchains.launcherFor {
78-
languageVersion.set(JavaLanguageVersion.of(11))
79-
vendor.set(JvmVendorSpec.matching("GraalVM"))
78+
languageVersion.set(JavaLanguageVersion.of(17))
79+
// vendor.set(JvmVendorSpec.matching("Oracle Corporation"))
8080
}
8181

8282
def fullFunctionalTest = tasks.register("fullFunctionalTest")
8383

8484
['functionalTest', 'configCacheFunctionalTest'].each { baseName ->
85-
["current", "7.4", "7.6.2"].each { gradleVersion ->
85+
["current", "7.4", "7.6.2", "8.0.1"].each { gradleVersion ->
8686
String taskName = gradleVersion == 'current' ? baseName : "gradle${gradleVersion}${baseName.capitalize()}"
8787
// Add a task to run the functional tests
8888
def testTask = tasks.register(taskName, Test) {
@@ -105,6 +105,14 @@ def fullFunctionalTest = tasks.register("fullFunctionalTest")
105105
javaLauncher.set(graalVm)
106106
if (baseName == 'configCacheFunctionalTest') {
107107
systemProperty('config.cache', 'true')
108+
// These args are required so that we can debug tests which
109+
// run with the configuration cache, see https://github.com/gradle/gradle/issues/25898
110+
jvmArgs = [
111+
'--add-opens=java.base/java.lang=ALL-UNNAMED',
112+
'--add-opens=java.base/java.util=ALL-UNNAMED',
113+
'--add-opens=java.base/java.lang.invoke=ALL-UNNAMED',
114+
'--add-opens=java.base/java.net=ALL-UNNAMED',
115+
]
108116
}
109117
}
110118
fullFunctionalTest.configure {

common/junit-platform-native/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ dependencies {
6161

6262
apply from: "gradle/native-image-testing.gradle"
6363

64-
test {
64+
tasks.named('test') {
6565
doFirst {
6666
delete { delete testIdsDir.get().asFile }
6767
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,25 @@ public void onLoad(NativeImageConfiguration config) {
8181
"org.junit.jupiter.engine.execution.ConditionEvaluator",
8282
"org.junit.jupiter.engine.execution.ExecutableInvoker",
8383
"org.junit.jupiter.params.provider.EnumSource$Mode",
84+
// new in Junit 5.10
85+
"org.junit.platform.launcher.core.LauncherConfig",
86+
"org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter"
8487
};
8588
for (String className : buildTimeInitializedClasses) {
8689
config.initializeAtBuildTime(className);
8790
}
8891

89-
try {
90-
Class <?> executor = Class.forName("org.junit.jupiter.engine.extension.TimeoutExtension$ExecutorResource");
91-
config.registerAllClassMembersForReflection(executor);
92-
} catch (ClassNotFoundException e) {
93-
debug("Failed to register class for reflection. Reason: %s", e);
92+
String[] registeredForReflection = {
93+
"org.junit.jupiter.engine.extension.TimeoutExtension$ExecutorResource",
94+
"org.junit.jupiter.engine.extension.TimeoutInvocationFactory$SingleThreadExecutorResource"
95+
};
96+
for (String className : registeredForReflection) {
97+
try {
98+
Class <?> executor = Class.forName(className);
99+
config.registerAllClassMembersForReflection(executor);
100+
} catch (ClassNotFoundException e) {
101+
debug("Failed to register class for reflection. Reason: %s", e);
102+
}
94103
}
95104
}
96105

docs/src/docs/asciidoc/gradle-plugin.adoc

+41
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,47 @@ include::../snippets/gradle/kotlin/build.gradle.kts[tags=include-metadata]
449449

450450
For more advanced configurations you can declare a `org.graalvm.buildtools.gradle.tasks.CollectReachabilityMetadata` task and set the appropriate properties.
451451

452+
[[pgo-support]]
453+
== Profile-guided optimizations
454+
455+
The plugin supports building images with https://www.graalvm.org/latest/reference-manual/native-image/guides/optimize-native-executable-with-pgo/[Profile-Guided Optimizations].
456+
457+
It works in 3 phases:
458+
459+
- the first one consists in generating a binary with instrumentation enabled
460+
- the second phase consists in running the binary in order to gather profiling information
461+
- the third phase consists in compiling the binary with the generated profile
462+
463+
In order to generate a binary with instrumentation enabled, you should run the `nativeCompile` command with the `--pgo-instrument` command line option:
464+
465+
`./gradlew nativeCompile --pgo-instrument`
466+
467+
This will generate a binary under `build/native/nativeCompile` with the `-instrumented` suffix.
468+
You can run the binary to gather profiling data:
469+
470+
[source,bash]
471+
----
472+
$ cd build/native/nativeCompile/
473+
$ ./my-application-instrumented`
474+
----
475+
476+
A `default.iprof` file will be generated once the application is stopped.
477+
Alternatively, you can have Gradle both generate and run the instrumented binary in a single command by running:
478+
479+
`./gradlew nativeCompile --pgo-instrument nativeRun`
480+
481+
In which case the profile will automatically be stored into `build/native/nativeCompile`.
482+
483+
The last phase consists in copying the generated profile, so that it's automatically used when building the native binary.
484+
The conventional location for profiles is `src/pgo-profiles/<name of the binary>`.
485+
By default, we're using the `main` binary so the location will be `src/pgo-profiles/main`.
486+
Copy the `default.iprof` file into that directory, then run:
487+
488+
`./gradlew nativeCompile`
489+
490+
The profile will automatically be used and the binary compiled with PGO.
491+
It is possible to include more than one profile, in which case you should rename the `.iprof` files in the `src/pgo-profiles/main` directory.
492+
452493
[[plugin-configurations]]
453494
== Configurations defined by the plugin
454495

docs/src/docs/asciidoc/index.adoc

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ If you are using alternative build systems, see <<alternative-build-systems.adoc
1919
[[changelog]]
2020
== Changelog
2121

22+
=== Release 0.9.24
23+
24+
==== Gradle plugin
25+
26+
* Add support for PGO
27+
2228
=== Release 0.9.23
2329

2430
* Upgrade metadata to 0.3.2

gradle/libs.versions.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ mavenEmbedder = "3.8.6"
1111
mavenWagon = "3.4.3"
1212
graalvm = "22.0.0"
1313
jackson = "2.13.3"
14-
junitPlatform = "1.8.1"
15-
junitJupiter = "5.8.1"
14+
junitPlatform = "1.9.3"
15+
junitJupiter = "5.10.0"
1616
aether = "1.1.0"
1717
slf4j = "1.7.9"
1818
groovy = "3.0.11"
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)