Skip to content

Commit

Permalink
Set up GraalVM Native Image
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 2, 2024
1 parent 45b3a4a commit 78132e8
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 4 deletions.
36 changes: 33 additions & 3 deletions .github/workflows/kt-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,34 @@ jobs:
name: ${{ matrix.target }}-benchmarks
path: kt/aoc2024-exe/build/reports/benchmarks

graalvm:
needs: [ assemble, get-inputs ]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: inputs
path: inputs
- uses: graalvm/setup-graalvm@v1
with:
java-version: 21
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: true
- run: ./gradlew --no-configuration-cache -Pagent nativeBenchmarkRun
working-directory: kt
env:
AOC2024_DATADIR: ${{ github.workspace }}/inputs
- uses: actions/upload-artifact@v4
with:
name: graalvm-benchmarks
path: kt/graalvm/build/reports/benchmarks

docs:
needs: [ jmh-visualizer, build ]
needs: [ jmh-visualizer, build, graalvm ]
runs-on: ubuntu-latest

steps:
Expand All @@ -97,13 +123,17 @@ jobs:
with:
name: linuxX64-benchmarks
path: benchmarks
- uses: actions/download-artifact@v4
with:
name: graalvm-benchmarks
path: benchmarks
- run: rm -rf jmh-visualizer
- run: unzip -d jmh-visualizer jmh-visualizer.zip
- name: Create provided.js
run: |
shopt -s failglob
shopt -s failglob globstar
names=() jsonargs=()
for file in benchmarks/main/*/*.json; do
for file in benchmarks/**/*.json; do
name=${file##*/}
name=${name%.*}
name=${name%Bench}
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/kt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ jobs:
name: aoc2024-js
path: kt/build/js/packages/aoc2024-aoc2024-exe/kotlin/*

graalvm:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: graalvm/setup-graalvm@v1
with:
java-version: 21
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: gradle/actions/setup-gradle@v4
- run: ./gradlew --no-configuration-cache nativeTest nativeCompile
working-directory: kt
- uses: actions/upload-artifact@v4
with:
name: aoc2024-native
path: kt/graalvm/build/native/nativeCompile/*

run-jvm:
needs: [ get-inputs, build ]
runs-on: ubuntu-latest
Expand All @@ -68,6 +85,23 @@ jobs:
env:
AOC2024_DATADIR: inputs

run-graalvm:
needs: [ get-inputs, graalvm ]
runs-on: ubuntu-latest

steps:
- uses: actions/download-artifact@v4
with:
name: inputs
path: inputs
- uses: actions/download-artifact@v4
with:
name: aoc2024-native
- run: chmod +x aoc2024-native
- run: ./aoc2024-native
env:
AOC2024_DATADIR: inputs

run-native:
needs: [ get-inputs, build ]
runs-on: ubuntu-latest
Expand Down
22 changes: 22 additions & 0 deletions kt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,25 @@ Run all checks, including [Detekt](https://detekt.github.io/) static code analys
```sh
./gradlew check
```

## [GraalVM](https://www.graalvm.org/)

Run the test suite as a GraalVM Native Image:

```sh
export GRAALVM_HOME=...
./gradlew --no-configuration-cache :graalvm:nativeTest
```

Run [JMH](https://openjdk.java.net/projects/code-tools/jmh/) benchmarks as a GraalVM Native Image:

```sh
export GRAALVM_HOME=...
./gradlew --no-configuration-cache -Pagent :graalvm:nativeBenchmarkRun
```

Print solutions for the inputs provided in local data files as a GraalVM Native Image:

```sh
./gradlew --no-configuration-cache :graalvm:nativeRun
```
23 changes: 23 additions & 0 deletions kt/aoc2024-exe/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,26 @@ benchmark {
}
}
}

afterEvaluate {
val jvmBenchBenchmarkJar by tasks.existing
configurations.consumable("jvmBenchmark") {
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
objects.named(TargetJvmEnvironment.STANDARD_JVM),
)
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.JAR),
)
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED))
}
outgoing {
capability("com.github.ephemient.aoc2024:aoc2024-bench:1.0")
artifact(jvmBenchBenchmarkJar)
}
}
}
60 changes: 60 additions & 0 deletions kt/aoc2024-lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,66 @@ kotlin {
}
}

val jvmTestCompilation = kotlin.jvm().compilations.getByName("test")
val jvmTestJar by tasks.registering(Jar::class) {
group = BasePlugin.BUILD_GROUP
description = "Assembles an archive containing the test classes."
archiveClassifier = "test"
from(jvmTestCompilation.output.allOutputs)
}
for ((name, base, usage) in listOf(
Triple("jvmTestApiElements", "jvmTestApi", Usage.JAVA_API),
Triple("jvmTestRuntimeElements", "jvmTestRuntimeClasspath", Usage.JAVA_RUNTIME),
)) {
configurations.consumable(name) {
extendsFrom(configurations.getByName(base))
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
objects.named(TargetJvmEnvironment.STANDARD_JVM),
)
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.JAR),
)
attribute(Usage.USAGE_ATTRIBUTE, objects.named(usage))
}
outgoing {
capability("com.github.ephemient.aoc2024:aoc2024-test:1.0")
artifact(jvmTestJar) {
type = ArtifactTypeDefinition.JAR_TYPE
}
variants.create("classes") {
attributes {
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.CLASSES),
)
}
for (classesDir in jvmTestCompilation.output.classesDirs) {
artifact(classesDir) {
type = ArtifactTypeDefinition.JVM_CLASS_DIRECTORY
builtBy(jvmTestCompilation.compileTaskProvider)
}
}
}
variants.create("resources") {
attributes {
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.RESOURCES),
)
}
artifact(jvmTestCompilation.output.resourcesDir) {
type = ArtifactTypeDefinition.JVM_RESOURCES_DIRECTORY
builtBy(jvmTestCompilation.processResourcesTaskName)
}
}
}
}
}

dependencies {
detektPlugins(libs.bundles.detekt.plugins)
}
Expand Down
94 changes: 94 additions & 0 deletions kt/graalvm/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.function.Predicate

plugins {
application
alias(libs.plugins.native.image)
}

application {
mainClass.set("com.github.ephemient.aoc2024.exe.Main")
}

val benchmarkDir = layout.buildDirectory
.dir(
"reports/benchmarks/main/" +
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME).replace(':', '.')
)

val benchmark by sourceSets.creating
val benchmarkRun by tasks.registering(JavaExec::class) {
System.getenv("GRAALVM_HOME")?.ifEmpty { null }?.let { setExecutable("$it/bin/java") }
mainClass = "org.openjdk.jmh.Main"
classpath(benchmark.output, benchmark.runtimeClasspath)
args("-f", 0, "-wi", 1, "-w", "0s", "-r", "0s", "-bm", "avgt", "-tu", "us", "-i", 1)
args("-rf", "json", "-rff", "/dev/null")
outputs.dir(AgentConfigurationFactory.getAgentOutputDirectoryForTask(layout, name))
}
val syncBenchmarkRunMetadata by tasks.registering(Sync::class) {
into(layout.buildDirectory.dir("generated/resources/benchmark"))
from(benchmarkRun) {
into("META-INF/native-image/com.github.ephemient.aoc2024/benchmark")
}
}
graalvmNative {
binaries {
getByName("main") {
imageName = "aoc2024-native"
}
create("benchmark") {
imageName = "aoc2024-native-benchmark"
mainClass = "org.openjdk.jmh.Main"
classpath(syncBenchmarkRunMetadata, benchmark.output, benchmark.runtimeClasspath)
runtimeArgs("-f", 0, "-wi", 1, "-w", "1s", "-r", "1s", "-bm", "avgt", "-tu", "us")
val benchmarkFile = benchmarkDir.get().file("graalvmBench.json")
runtimeArgs("-rf", "json", "-rff", benchmarkFile.asFile)
findProperty("benchmarkInclude")?.let { runtimeArgs("-e", it) }
findProperty("benchmarkExclude")?.let { runtimeArgs(it) }
}
}
agent {
tasksToInstrumentPredicate = Predicate { it.name == "benchmarkRun" }
}
}
tasks.named("nativeBenchmarkRun") {
val benchmarkDir = benchmarkDir.get()
outputs.file(benchmarkDir.file("graalvmBench.json"))
doFirst { benchmarkDir.asFile.mkdirs() }
}

val externalTestClasses = configurations.dependencyScope("externalTestClasses")
val externalTestClasspath = configurations.resolvable("externalTestClasspath") {
extendsFrom(externalTestClasses.get())
isTransitive = false
attributes {
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements.CLASSES),
)
}
}
configurations.testImplementation {
extendsFrom(externalTestClasses.get())
}
tasks.named<Test>("test") {
testClassesDirs = files(testClassesDirs, externalTestClasspath.get())
useJUnitPlatform()
}

dependencies {
implementation(projects.aoc2024Exe)
testImplementation(libs.junit.jupiter.api)
externalTestClasses(projects.aoc2024Lib) {
capabilities {
requireCapability("com.github.ephemient.aoc2024:aoc2024-test:1.0")
}
}
benchmark.implementationConfigurationName(projects.aoc2024Exe) {
capabilities {
requireCapability("com.github.ephemient.aoc2024:aoc2024-bench:1.0")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Args = --initialize-at-build-time=org.openjdk.jmh.infra,org.openjdk.jmh.util.Utils,org.openjdk.jmh.runner.InfraControl,org.openjdk.jmh.runner.InfraControlL0,org.openjdk.jmh.runner.InfraControlL1,org.openjdk.jmh.runner.InfraControlL2,org.openjdk.jmh.runner.InfraControlL3,org.openjdk.jmh.runner.InfraControlL4
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Args = --initialize-at-build-time=kotlin.annotation.AnnotationRetention,kotlin.annotation.AnnotationTarget
2 changes: 2 additions & 0 deletions kt/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ junit-jupiter = "5.11.3"
kotlin = "2.1.0"
kotlinx-benchmark = "0.4.13"
kotlinx-coroutines = "1.9.0"
native-image = "0.10.3"
okio = "3.9.1"

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-plugin-allopen = { id = "org.jetbrains.kotlin.plugin.allopen", version.ref = "kotlin" }
kotlinx-benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "kotlinx-benchmark" }
native-image = { id = "org.graalvm.buildtools.native", version.ref = "native-image" }

[libraries]
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
Expand Down
2 changes: 1 addition & 1 deletion kt/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ gradle.afterProject {
}

rootProject.name = "aoc2024"
include("aoc2024-exe", "aoc2024-lib")
include("aoc2024-exe", "aoc2024-lib", "graalvm")

0 comments on commit 78132e8

Please sign in to comment.