<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Hi Matthias!<br>
<br>
I've rewritten the benchmark slightly (just to make them "normalized" the way we use to write them) even though your benchmarks work equally well. See attachment. By using the commands <br>
<br>
</div>
<div class="elementToProof" style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace; font-size: 12pt; color: rgb(0, 0, 0);">
jvmArgsAppend = {</div>
<pre><div class="elementToProof" style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace; font-size: 12pt; color: rgb(0, 0, 0);"> "-XX:+PrintCompilation",<br> "-XX:+UnlockDiagnosticVMOptions",<br> "-XX:+PrintInlining" }</div></pre>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
in a <span style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace;">
@Fork</span> annotation, and observing the output, it appears all the methods are inlined properly. So, even though some methods are more complex, it appears they are treated in the same way when it comes to inlining.<br>
<br>
By looking at the actual assembly generated for the benchmarks using these commands (for an M1 in my case):<br>
<br>
</div>
<pre><div class="elementToProof" style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace; font-size: 12pt; color: rgb(0, 0, 0);">@Fork(value = 1, jvmArgsAppend = {<br> "-Xbatch",<br> "-XX:-TieredCompilation",<br> "-XX:CompileCommand=dontinline,org.openjdk.bench.java.lang.foreign.Alignment::findAligned*",<br> "-XX:CompileCommand=PrintAssembly,org.openjdk.bench.java.lang.foreign.Alignment::findAligned*"<br>})</div></pre>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
I can see that the C2 compiler is able to unroll the segment access in the <span style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace;">
findAligned</span> method but not in the <span style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace;">
findAlignedNext method. </span>This is one reason<span style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace;"> findAligned</span> is faster. In order to see real assembly, the "hsdis-aarch64.dylib" must be present and it is recommended
to use a "fast-debug" version of the JDK. Read more on Jorn Vernee's blog here: <a href="https://jornvernee.github.io/hsdis/2022/04/30/hsdis.html" id="LPlnk828414">
https://jornvernee.github.io/hsdis/2022/04/30/hsdis.html</a></div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
The question then becomes why that is the case. This drives us into another field of expertise where I am not the right person to provide an answer. Generally, there is no guarantee as to how the C2 compiler works and we are improving it continuously. Maybe
someone else can provide additional information.</div>
<div class="elementToProof" style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Best, Per Minborg</div>
<div class="elementToProof" style="font-family: "Aptos Mono", Aptos_EmbeddedFont, Aptos_MSFontService, monospace; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
<br>
<br>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> panama-dev <panama-dev-retn@openjdk.org> on behalf of Matthias Ernst <matthias@mernst.org><br>
<b>Sent:</b> Wednesday, December 18, 2024 9:26 AM<br>
<b>To:</b> panama-dev@openjdk.org <panama-dev@openjdk.org><br>
<b>Subject:</b> performance: arrayElementVarHandle / calculated index / aligned vs unaligned</font>
<div> </div>
</div>
<div>
<div dir="ltr">Hi,
<div><br>
</div>
<div>I'm trying to use the foreign memory api to interpret some variable-length encoded data, where an offset vector encodes the start offset of each stride. Accessing element `i` in this case involves reading `offset[i+1]` in addition to `offset[i]`. The offset
vector is modeled as a `JAVA_LONG.arrayElementVarHandle()`.</div>
<div><br>
</div>
<div>Just out of curiosity about bounds and alignment checks I switched the layout to JAVA_LONG_UNALIGNED for reading (data is still aligned) and I saw a large difference in performance where I didn't expect one, and it seems to boil down to the computed index
`endOffset[i+1]` access, not for the `[i]` case. My expectation would have been that all variants exhibit the same performance, since alignment checks would be moved out of the loop.<br>
<br>
</div>
<div>A micro-benchmark (attached) to demonstrate:</div>
<div>long-aligned memory segment, looping over the same elements in 6 different ways:</div>
<div>{aligned, unaligned} x {segment[i] , segment[i+1], segment[i+1] (w/ base offset) } gives very different results for aligned[i+1] (but not for aligned[i]):<br>
<br>
Benchmark Mode Cnt Score Error Units<br>
Alignment.findAligned thrpt 217.050 ops/s<br>
Alignment.findAlignedPlusOne thrpt 110.366 ops/s. <= #####<br>
Alignment.findAlignedNext thrpt 110.377 ops/s. <= #####<br>
Alignment.findUnaligned thrpt 216.591 ops/s<br>
Alignment.findUnalignedPlusOne thrpt 215.843 ops/s<br>
</div>
<div>Alignment.findUnalignedNext thrpt 216.483 ops/s</div>
<div>
<div><br>
</div>
</div>
<div>openjdk version "23.0.1" 2024-10-15<br>
OpenJDK Runtime Environment (build 23.0.1+11-39)<br>
OpenJDK 64-Bit Server VM (build 23.0.1+11-39, mixed mode, sharing)</div>
<div>Macbook Air M3</div>
<div><br>
</div>
<div>Needless to say that the difference was smaller with more app code in play, but large enough to give me pause. Likely it wouldn't matter at all but I want to have a better idea which design choices to pay attention to. With the foreign memory api, I find it
a bit difficult to distinguish convenience from performance-relevant options (e.g. using path expressions vs computed offsets vs using a base offset. Besides "make layouts and varhandles static final" what would be other rules of thumb?)</div>
<div><br>
</div>
<div>Thx</div>
<font color="#888888">
<div>Matthias</div>
<div><br>
</div>
</font></div>
</div>
</body>
</html>