Was someone able to get AOT cache going for faster...
# compose-desktop
u
Was someone able to get AOT cache going for faster startup? (java 25)
p
I was playing with it. My app with aot cache starts in around 400ms, while without 800ms. But aot cache size was around 50mb. If implementing some logic to start gather cache on first run and after use it, may be it is ok. But distributing app with additional 50mb cache to win 400ms...
u
Well depends on what kind of app it is, big app, sure doesnt matter, but small utilities that basically are just compose & network at most..worth it imo
p
Yes. Should measure and decide for each project.
u
any pointers as how to do it? are you using java 25?
btw curious how do you measure app start? whats "app started" point for you? window created?
p
I was testing using java 24. App started mean all components loaded, initialized and start serving. Window opening in my app is launched in separate coroutine after initialize state but before start. So it is not measuring.
I'll search for aot usage. One moment.
On first run for generating cache
Copy code
java -XX:AOTCacheOutput=path-to-cache.aot -jar app.jar
on other runs using generated cache
Copy code
java -XX:AOTCache=path-to-cache.aot -jar app.jar
u
hmm and it captures everything until you cmd+c it?
p
Yes
u
java 25 supposedly automates this.. somehow but I wasnt able to get kgp with 25 going
p
For that case in my app i made cmd parameter (like dryRun). With this flaf my app after start just shutdown
Why do you need kgp for aot?
u
well java 25 supposedly makes this bit easier, just one flag, doesnt have to be manual although im not sure how it would know when to stop etc
okay so you
./gradlew packageReleaseUberJarForCurrentOS
produce the release jar as usual and then do the training run manually? or does it somehow integrate with gradle?
p
For stop you can make in your app smth like dry run
For now i'm experementing manualy. But you can make JavaExec Gradle task where you can execute your built app with -XX:AOTCacheOutput=path-to-cache.aot and make one more task for package resulting cache with your app
u
yea im just wondering if its not integrated somehow already; its not that new but if not yea ill just string it manually
p
If you expecting to include it in build process for Compose Desktop for example, it worth creating YT issue for it. May be JB team will include it in some releases
u
I'd expect the jvm.kgp to enabled it, as its a java feature
okay thank you!
btw do you know of any other knobs I might use to speed compose desktop up? on android, release build is significantly faster, to the point I'm not sure its just R8 doing it's magic -- has to be some compose flag as well that's being flipped
p
I'm using R8 also for optimizing desktop app jar.
u
hmm, how? is that a gradle plugin? or manually with r8.jar as well?
p
I've created Gradle task for it. One moment
u
did you have to turn off proguard from the release task as well?
p
I'm using own build tasks for creating desktop app jar
u
and what exactly do they do? is it just classic far jar + r8? or some config flags flipping as well?
p
Copy code
fun registerR8Task(project: Project, appJarFile: Provider<RegularFile>) {

    val r8Config = project.configurations.register("r8") {
        project.dependencies.add(name, "com.android.tools:r8:<r8 version>")
    }
    project.tasks.register("r8", JavaExec::class.java) {

        val outFile: RegularFile = TODO("provide file for output")

        inputs.file(appJarFile)
        outputs.file(outFile)
        classpath(r8Config)
        mainClass.set("com.android.tools.r8.R8")
        //
        doFirst {
            val theLauncher = javaLauncher.get()
            args(
                "--release",
                "--classfile",
                "--output", outFile.asFile.absolutePath,
                "--lib", theLauncher.metadata.installationPath,
                appJarFile.get().asFile.absolutePath
            )
        }
    }
}
Here is how you can create task that takes your app jar file, process it by R8 and put resulting jar file to provided path
R8 rules should be located in META-INF/com.android.tools/r8/*.pro files in app jar
Before this step i'm using Shadow jar task to make single fat jar
u
okay so classic shadow jar, nothing special, is the input to this?
p
Yes. Nothing special.
Output file of Shadow jar task is going as input to R8 task
Only thing that should to be checked are R8 rules files. As i mention they should be located in META-INF/com.android.tools/r8/*.pro files in app fat jar
u
hmm do I need to download them myself for compose?
a
I actually already implemented it, but turns out AppCDS is broken for the scenario of distributable desktop apps. I’m working with the JBR team on a fix though.
You can follow the ticket here: https://youtrack.jetbrains.com/issue/CMP-8338
u
btw appcds is not the same as aot cache, right?
a
I’m not sure. What’s the difference?
u
I figured it's 2 things, but I'm a novice at thise -- just checking
a
u
well @PHondogo said he has it working by simply the official 2 commands ..but okay im out of my depth soz
a
It says the classpath in the record run has to match the runtime classpath, so it has the same problem as AppCDS
u
hm why would it not?
a
AppCDS (and, I assume AOT) works fine when you execute the “collection” run on the same machine, in the same directory as the “real” run.
It doesn’t work if you try to ship an app with the AOT/AppCDS cache already built-in.
Because the classpaths don’t match.
u
whats the use case for it then? nobody is going to do the training run on prod machines, even say on servers
I see -- so if I were to bundle jre? would that then be fine?
The use case is exactly on servers
u
again im a noob, but I'd expect the training runs to be part of the CICD deploy, so somewhere on some CICD machine, no? not the actual prod machine
a
If you run in Docker then the environment is identical to the build environment. You can also do the collection run after deployment if you prefer.
u
but this is all predicated on running on system JRE, which can be basically anywhere -- which then breaks the aot stuff?
a
Compose apps already ship with the JRE bundled
On servers you’re also in full control of the JRE
So that’s not the problem
u
so even if the jre is bundled, and I precisely know its version, location etc, even then it breaks?
a
Read the last link I posted
u
I'm reading it but another dimension to this is it's a JBR thing right? I can bundle any vendor jvm I want technically, right? so in theory say azul should be good?
a
Yes, but afaik all JVMs have this problem
When/if we fix it in JBR, you’ll be able to use AppCDS/AOT if you choose JBR.
and maybe eventually the fix will get upstreamed.
u
I see great thank you! noob question .. upstreamed..where? is there like a master jvm impl?
a
OpenJDK. Most JVMs are forks of it.
u
oh, i see, thanks!
if I may one more .. there is a future where all this stuff is used by gradle, so my build is faster as well?
or is that pointless since kotlin/gradle has the daemon
a
The latter, I imagine
👍 1