<div dir="ltr">Continuing from this, I ran it against the reference C++ implementation and got these numbers.<br><br><font face="monospace"># Reference C++ implementation (-O3)</font><br><br><font face="monospace">```</font><br><font face="monospace">real 6m35.702s</font><br><font face="monospace">user 6m33.780s</font><br><font face="monospace">sys 0m1.454s</font><br><font face="monospace">```</font><br><font face="monospace"> </font><br><font face="monospace"># Java With Value Classes</font><br><br><font face="monospace">```</font><br><font face="monospace">real 11m50.122s</font><br><font face="monospace">user 11m36.536s</font><br><font face="monospace">sys 0m13.281s</font><br><font face="monospace">```</font><br><br><font face="monospace"># Java Without Value Classes</font><br><br><font face="monospace">```</font><br><font face="monospace">real 17m1.038s</font><br><font face="monospace">user 16m40.993s</font><br><font face="monospace">sys 0m29.400s</font><br><font face="monospace">```</font><br><br><font face="arial, sans-serif">I am wondering if using an AOT cache could help catch up to the C++, but I get a class file version error running with </font><font face="monospace">-XX:AOTCache=value.aot</font><br><font face="arial, sans-serif"><br></font><font face="monospace">Error: LinkageError occurred while loading main class Main<br> java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 70.0), this version of the Java Runtime only recognizes class file versions up to 69.0</font><font face="arial, sans-serif"></font></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Wed, Oct 29, 2025 at 3:44 PM Sergey Kuksenko <<a href="mailto:sergey.kuksenko@oracle.com">sergey.kuksenko@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 Ethan,<br>
<br>
Thank you for the information. Your example and the code are pretty straightforward, and I was able to repeat and diagnose the issue.<br>
<br>
The fact is, the performance issue is not directly related to value classes. The problem is that HittableList::hit method (invoked at Camera::rayColor) was inlined by JIT in the non-value version and wasn't inlined in the value classes version.<br>
When you inline that invocation manually, you should get the same performance for both versions.<br>
HittableList::hit was not inlined in the value classes version because value classes resulted in a different code size and changed the inline heuristics. It's a mainline issue; you'll encounter it quite rarely. Current inline heuristics work well in 99% of cases, and you should be very lucky (or unlucky) to get it in real life.<br>
<br>
Best regards,<br>
Sergey Kuksenko<br>
<br>
<br>
<br>
________________________________________<br>
From: valhalla-dev <<a href="mailto:valhalla-dev-retn@openjdk.org" target="_blank">valhalla-dev-retn@openjdk.org</a>> on behalf of Ethan McCue <<a href="mailto:ethan@mccue.dev" target="_blank">ethan@mccue.dev</a>><br>
Sent: Monday, October 27, 2025 5:08 PM<br>
To: <a href="mailto:valhalla-dev@openjdk.org" target="_blank">valhalla-dev@openjdk.org</a><br>
Subject: Raytracing Experience Report<br>
<br>
Hi all,<br>
<br>
I have been following along in the "Ray Tracing in a Weekend" book and trying to make as many classes as possible value classes. (Vec3, Ray, etc.)<br>
<br>
<a href="https://github.com/bowbahdoe/raytracer" rel="noreferrer" target="_blank">https://github.com/bowbahdoe/raytracer</a><br>
<br>
<a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html" rel="noreferrer" target="_blank">https://raytracing.github.io/books/RayTracingInOneWeekend.html</a><br>
<br>
(without value classes)<br>
<br>
time java --enable-preview --class-path build/classes Main > image.ppm<br>
<br>
real 4m33.190s<br>
user 4m28.984s<br>
sys 0m5.511s<br>
<br>
(with value classes)<br>
<br>
time java --enable-preview --class-path build/classes Main > image.ppm<br>
<br>
real 3m54.623s<br>
user 3m52.205s<br>
sys 0m2.064s<br>
<br>
So by the end the version using value classes beats the version without them by ~14% using unscientific measurements.<br>
<br>
But that is at the end, running the ray tracer on a relatively large scene with all the features turned on. Before that point there were some checkpoints where using value classes performed noticeably worse than the equivalent code sans the value modifier<br>
<br>
<a href="https://github.com/bowbahdoe/raytracer/tree/no-value-faster" rel="noreferrer" target="_blank">https://github.com/bowbahdoe/raytracer/tree/no-value-faster</a><br>
<br>
real 1m22.172s<br>
user 1m9.871s<br>
sys 0m12.951s<br>
<br>
<a href="https://github.com/bowbahdoe/raytracer/tree/with-value-slower" rel="noreferrer" target="_blank">https://github.com/bowbahdoe/raytracer/tree/with-value-slower</a><br>
<br>
real 3m34.440s<br>
user 3m19.656s<br>
sys 0m14.870s<br>
<br>
So for some reason just adding value to the records/classes makes the program run a over 2x as slow.<br>
<br>
<a href="https://github.com/bowbahdoe/raytracer/compare/no-value-faster...with-value-slower" rel="noreferrer" target="_blank">https://github.com/bowbahdoe/raytracer/compare/no-value-faster...with-value-slower</a><br>
<br>
Is there some intuition that explains this? I am on a stock M1 Arm Mac.<br>
</blockquote></div>