<div dir="ltr"><div dir="auto"><div dir="ltr">Hi Ioi, and thanks for getting back to me.<div><div><br></div><div>> The Leyden design philosophy is that the training/assembly should be done in an environment as close to the production run as possible</div><div><br><div>While I understand this reasoning, there are cases were this is not really convenient or possible. Overall, I believe it would be great to see a general solution to the distribution of CLI/desktop programs (meant to be installed on user machines) from the Leyden team.</div></div></div><div><br></div><div>> In your scenario, since you are creating the AOT cache on first execution, would it be possible to do a training run on first execution as well?</div><div><br></div><div dir="auto">Also, if we implement it during the user's first run, the training would heavily depend on their command choices. What if they just ran "./amper --help"? Adding logic to detect whether the command they run is suitable for training complicates matters significantly, as CLI argument parsing currently happens within the JVM app, not the wrapper script (which determines the JVM arguments). This doesn't look like a good general solution for CLI applications.</div><div dir="auto"><br></div><div dir="auto">> For short running programs such as command-line tools, I think the training run can be relatively short, and should take less time than it takes to create the AOT cache</div><div dir="auto"><br></div><div dir="auto">Doing a training run for our application means running a build (because Amper is a build tool). This is most likely not short, especially on a fresh user machine, and particularly if it involves building multiplatform stuff. It could take 5 minutes for all I know.</div><div dir="auto"><br></div><div dir="auto">For the record, I tried to explore alternatives here for Amper specifically: <a href="https://youtrack.jetbrains.com/issue/AMPER-4825/AOT-caching-for-Amper-CLI#focus=Comments-27-12950737.0-0">https://youtrack.jetbrains.com/issue/AMPER-4825/AOT-caching-for-Amper-CLI#focus=Comments-27-12950737.0-0</a></div><div dir="auto"><br></div><div>1. We could move the training run to the `./amper update` command (which might also be run as part of Amper's installation). This involves generating a training project, running a build as a training run, and generating the cache. This would likely make the update longer than acceptable. The AOT cache generation is already probably too much, but we don't really have a choice there if we don't want a complicated CI setup.</div><div>2. We could make the training run explicit and project-specific, by asking the user to run a specific command. This is not ideal because users must know it exists, and most users will not benefit from it.</div><div>3. We could create a whole CI infrastructure with different types of machines, each building the proper AOT cache for various OS and architecture combinations. This is a CI hassle, and kinda goes against "write once run anywhere" experience I would expect from the JVM world. </div><div>4. Use a GraalVM native image instead, but this also might require some CI hassle.</div><div dir="auto"><br></div><div dir="auto">> Technically it's not impossible to support an alternative format for the AOT configuration file to be portable. We probably need a way to serialize the existing contents into a text file, and then read it back in the AOT assembly phase</div><div dir="auto"><br></div><div>Thanks, that gives me some hope! By the way, I have seen text versus binary formats mentioned a couple of times, and I have to say I'm a bit confused. This seems orthogonal to portability. We could have a non-portable text format (with platform-specific classes) or a portable binary format (any custom binary format that is the same on all machines). But I'll assume that by "text" you mean "portable" and by "binary" you mean "non-portable".</div></div><div><br></div><div>> One disadvantage is it will not cover platform-dependent classes, so this could be sub-optimal (e.g., for programs that makes a lot of file operations).</div><div><br></div></div><div>That is a fair point I hadn't considered. Thanks for sharing. This could perhaps be mitigated if the JDK provided a way to perform training runs with emulation (but I might be dreaming here :D).</div><div>More seriously, this is a trade-off that some applications might be willing to make, especially if the AOT cache generation could be done in different variants from a single host, like some form of cross-compilation (which seems more realistic to my ignorant brain).</div><div><br></div><div>Perhaps building a native image is our best option right now.</div><div><br></div><div>Thanks,</div><div>Joffrey</div><div><br></div><div><div dir="auto"><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Fri, Nov 7, 2025 at 5:39 PM <<a href="mailto:ioi.lam@oracle.com" rel="noreferrer noreferrer" target="_blank">ioi.lam@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Joffrey,<br>
<br>
Thanks for you feedback.<br>
<br>
You're correct that we have changed the AOT configuration file to a <br>
binary format that's tied to the same JDK executable that generated it. <br>
It cannot be used on a different OS, or CPU, or even a different version <br>
of the JDK on the same OS/CPU.<br>
<br>
The Leyden design philosophy is that the training/assembly should be <br>
done in an environment as close to the production run as possible. In <br>
your scenario, since you are creating the AOT cache on first execution, <br>
would it be possible to do a training run on first execution as well? <br>
E.g, from something like:<br>
<br>
java -XX:AOTMode=create -XX:AOConfiguration=pregenerated.config <br>
-XX:AOTCache=app.aot<br>
<br>
to<br>
<br>
java -XX:AOTCacheOutput=app.aot -cp $JARS myapp.Training<br>
<br>
For short running programs such as command-line tools, I think the <br>
training run can be relatively short, and should take less time than it <br>
takes to create the AOT cache (especially when AOT code compilation is <br>
supported in the future). Therefore, I think this will not take <br>
significantly longer than your proposed approach.<br>
<br>
Technically it's not impossible to support an alternative format for the <br>
AOT configuration file to be portable. We probably need a way to <br>
serialize the existing contents into a text file, and then read it back <br>
in the AOT assembly phase. One disadvantage is it will not cover <br>
platform-dependent classes, so this could be sub-optimal (e.g., for <br>
programs that makes a lot of file operations).<br>
<br>
$ cd openjdk/src/java.base<br>
$ find windows -name \*.java | wc<br>
70 70 3745<br>
$ find linux -name \*.java | wc<br>
32 32 1804<br>
$ find macosx -name \*.java | wc<br>
36 36 2043<br>
<br>
Therefore, we are a bit hesitant to go back to the text-based config <br>
file due to development cost and performance implication.<br>
<br>
Thanks<br>
<br>
- Ioi<br>
<br>
<br>
On 11/5/25 3:21 AM, Joffrey Bion wrote:<br>
<br>
> Hi,<br>
><br>
> At JetBrains we're working on a JVM-based command-line tool called <br>
> Amper. We're trying to optimize startup time using AOT features, but <br>
> we're in a bit of a pickle regarding the AOT cache portability.<br>
><br>
> The way our application is setup is the following:<br>
> * we build our project, and package our runtime classpath jars into a <br>
> .tgz, which we call our "distribution". This is done from a single <br>
> (Linux) host on our CI.<br>
> * we provide a wrapper script to users, which they should check into <br>
> their VCS repo (akin to gradlew). This wrapper script downloads the <br>
> proper JRE for Amper and the distribution tgz (if they are not already <br>
> present on the machine), and then runs the application.<br>
><br>
> Our plan was the following:<br>
> * perform an AOT training run on a single CI host (the one that <br>
> publishes our application), record the amper.aotconf once, and package <br>
> it within our distribution tgz<br>
> * then, have our wrapper script generate the AOT cache from the <br>
> aotconf on the end user machine during the first run.<br>
><br>
> This way, we remove the training run hassle (and time overhead) from <br>
> the users, but still generate the OS/arch/environment-specific cache <br>
> on the end user machine.<br>
><br>
> However, it seems that the AOT config (output of the training run) <br>
> will no longer be portable:<br>
> <a href="https://bugs.openjdk.org/browse/JDK-8348426" rel="noreferrer noreferrer noreferrer" target="_blank">https://bugs.openjdk.org/browse/JDK-8348426</a><br>
><br>
> And the response here seems to confirm this:<br>
> <a href="https://mail.openjdk.org/pipermail/leyden-dev/2025-March/001781.html" rel="noreferrer noreferrer noreferrer" target="_blank">https://mail.openjdk.org/pipermail/leyden-dev/2025-March/001781.html</a><br>
><br>
> > In JDK 25 and going forward, we are collecting execution profile during<br>
> > AOT training. As a result, we have changed the AOT configuration <br>
> file to<br>
> > a binary file format that's tied to the execution platform of the JVM.<br>
> > You can see more information from<br>
> > <a href="https://bugs.openjdk.org/browse/JDK-8348426" rel="noreferrer noreferrer noreferrer" target="_blank">https://bugs.openjdk.org/browse/JDK-8348426</a><br>
> ><br>
> > The profile data is difficult to be represented in a cross-platform<br>
> > format (e.g., a text file). The need for "cross platform builds" has<br>
> > come up before in our design discussion. We have decided to defer it <br>
> and<br>
> > focus on delivering optimizations for the most common use cases first.<br>
> > We might re-evaluate this decision in the future when we have more user<br>
> > feedback (and more time :-)<br>
><br>
> So my question is: what is the plan of the project Leyden team <br>
> regarding our use case (non-server applications that run on different <br>
> types of user machines)? Are there any plans to allow app authors to <br>
> somehow bundle AOT data from a training run in a portable format <br>
> together with the jars of the application?<br>
> We're using the JVM for the "write once, run anywhere" benefit, so it <br>
> feels a bit awkward for us to create individual distributions for our <br>
> users (and it's a CI hassle). On the other hand, moving the training <br>
> run to the user machine means that we might have to expose part of <br>
> this to the users, or make them wait for a long time in some sort of <br>
> installation/optimization phase. Neither of these options are ideal, <br>
> hence why we're hoping for a solution right from the AOT feature.<br>
><br>
> Thanks a lot in advance,<br>
> Joffrey<br><br>
</blockquote></div>
</div>
</div></div>