<div dir="ltr">Dear JDK/Panama Devs,<div><br></div><div>In order to get to know the <font face="monospace"><i>jdk.incubator.vector</i> API</font>, I have been tinkering with the vectorization of the complex fast-Fourier transform (FFT) of tiny float arrays of length <font face="monospace"><i>FloatVector.SPECIES_PREFERRED.length()</i></font><font face="arial, sans-serif">. In the process, I have encountered some performance and usability issues which I want to share, in the hopes these might be addressed in a future iteration of the Vector API. My perspective is purely one of an API user, since I have no knowledge of the underlying AVX/SSE instruction sets. Actual knowledge of the FFT should not be necessary for this discussion. The performance and usability issues come down to a single line of code which I will get to in a second.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">As an experiment, I have taken a standard FFT implementation (without bit-reversal permutation) <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT.java#L81-L112">fftV1</a> and converted it into a vectorized version <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT.java#L114-L136">fftV2</a> which performs consecutive rearrangements and fma operatons using precomputed </font><font face="monospace"><i>VectorShuffles</i></font><font face="arial, sans-serif"> and </font><i style=""><font face="monospace">FloatVectors</font></i><font face="arial, sans-serif">. And fair enough, according to my <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT_Benchmark.java">benchmarks</a>, the vectorized version takes roughly 40% less time using AVX2 on an AMD R9 3900X.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Next, I have tried to be "clever". In a second vectorized variant <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT.java#L138-L160">fftV3</a>, every second </font><i style="font-family:monospace">VectorShuffle </i><font face="arial, sans-serif">is computed from every first of two </font><i style="font-family:monospace">VectorShuffles</i><font face="arial, sans-serif" style="">. In (my) theory, this should reduce the amount of cache required. Transforming a </font><i style="font-family:monospace">VectorShuffle</i><span style="font-family:monospace">,</span><font face="arial, sans-serif"> however, turned out much more cumbersome than I had hoped. The cleanest way I could come up with was the following:</font></div><div><ul><li><font face="arial, sans-serif">Find a </font><i style=""><font face="monospace">VectorSpecies<Byte></font></i><font face="arial, sans-serif"> with the same lane count as </font><i style="font-family:monospace">FloatVector.SPECIES_PREFERRED</i></li><li>Cast the <i style="font-family:monospace">VectorShuffle </i>to said species</li><li>Convert using <i style="font-family:monospace">VectorShuffle::toVector</i></li><li><font face="arial, sans-serif">Apply the transformation</font></li><li>Convert back using ByteVector<i style="font-family:monospace">.toShuffle()</i></li><li>Cast <i style="font-family:monospace">VectorShuffle<Byte> </i>back to <i style="font-family:monospace">VectorShuffle<Double></i></li></ul><div>The line of code in question can be found <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT.java#L147">here</a>. I have tried many other implementations of said line of code, all of which have been even more spaghetti-ish. All variants had one thing in common: Terrible performance. fftV3 takes twice as long to compute as the non-vectorized fftV1. My experience with these usability and performance issues lead me to the following suggestions/questions:</div></div><div><br></div><div><font size="4"><b>1) VectorShuffle should behave like or even be an IntVector</b></font></div><div>In my mind, a <i style="font-family:monospace">VectorShuffle</i> is nothing but a vector of indices. It would greatly simplify the API if it just were an <i style="font-family:monospace">IntVector</i> or a <i style="font-family:monospace">ShortVector</i>. If that is not possible, it would be great if it would at least support lanewise integral operations like ADD, SUB, OR, XOR,...</div><div><br></div><div><b style="font-size:large">2) Improve species selection</b><br></div><div>The aforementioned spaghetti code required me to find a <font face="arial, sans-serif">a </font><i><font face="monospace">VectorSpecies<Byte></font></i><font face="arial, sans-serif"> with the same lane count as </font><i style="font-family:monospace">FloatVector.SPECIES_PREFERRED</i>. To achieve that, I had to resort to <a href="https://github.com/DirkToewe/tiny_vectorized_fft/blob/master/src/main/java/tiny_vectorized_fft/TinyFFT.java#L17-L31">reflection</a>, which is never a good sign. Additional methods for species selection would be really helpful, the following come to mind:</div><div><ul><li>Add a static methods along the lines of <i style="font-family:monospace">FloatVector.speciesWithLaneCount(int)</i></li><li>Add a conversion methods to each species, something like <i><font face="monospace">VectorSpecies<Float>::toIntSpecies()</font></i></li><li>Add static methods, e.g. <i style="font-family:monospace">FloatVector.availableSpecies()</i>, that list all available species</li></ul><div><b style="font-size:large">3) Why is VectorSpecies type-dependent?</b><br></div></div><div>As my example above demonstrates, it is sometimes necessary to work with different vector types of the same lane count. If <i><font face="monospace">VectorSpecies </font></i>was not type-dependent, different types could simply be handled by a single species. This would also make <i style="font-family:monospace">VectorShuffle </i>type-independent. <i style="font-family:monospace">VectorShuffle::toVector </i>could always return an <i style="font-family:monospace">IntVector</i> instead of e.g. <i style="font-family:monospace">VectorShuffle<Double>::toVector</i> returning a <i style="font-family:monospace">DoubleVector</i> which is, in my opinion, unintuitive.</div><div><br></div><div><b style="font-size:large">4) Add VectorSpecies::loopBoundOptimized(int)</b><br></div><div>On an unrelated note: <i><font face="monospace">VectorSpecies::loopBound(int) </font></i>always returns the largest possible bound. While processing 9 elements with an 8-lane species, zero might still be the best loop bound. If a JRE does not support vectorization, zero might in fact always be the best loop bound. A method along the lines of <i><font face="monospace">VectorSpecies::loopBoundOptimized(int)</font></i> could allow the runtime more flexibility to determine an optimal loop bound, maybe even based on runtime benchmarks.</div><div><br></div><div>Hopefully, these suggestions and questions are constructive</div><div><br></div><div>Yours sincerely</div><div>Dirk</div></div>