Skip to content

Commit 2424053

Browse files
authored
mismatch part 2
1 parent efb0a84 commit 2424053

1 file changed

Lines changed: 50 additions & 2 deletions

File tree

_posts/2026-03-24-VectorAPI-control-flow.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,53 @@ CPU and the length of the arrays.
289289

290290
**Algorithm 4: mismatch**
291291

292-
TODO
292+
We want to find the first index at which two byte arrays `a` and `b` differ, or `-1` if they have no difference.
293+
This is inspired by
294+
[Arrays::mismatch](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/Arrays.html#mismatch(byte%5B%5D,byte%5B%5D)),
295+
and related method like `Arrays::equals` and `Arrays::compare` that can be implemented using `Arrays::mismatch`.
296+
All of these are backed by vectorized intrinsics.
297+
This benchmark is a newer addition to the [OpenJDK repository](https://github.com/openjdk/jdk/pull/30372).
298+
299+
Reference implementation:
300+
```java
301+
for (int i = 0; i < a.length; i++) {
302+
if (a[i] != b[i]) {
303+
return i;
304+
}
305+
}
306+
return -1;
307+
```
308+
309+
[Arrays::mismatch](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/Arrays.html#mismatch(byte%5B%5D,byte%5B%5D)) implementation:
310+
```java
311+
return Arrays.mismatch(a, b);
312+
```
293313

314+
[MemorySegment::mismatch](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/lang/foreign/MemorySegment.html#mismatch(java.lang.foreign.MemorySegment)) implementation:
294315
```java
295-
x
316+
var aMS = MemorySegment.ofArray(a);
317+
var bMS = MemorySegment.ofArray(b);
318+
return (int) aMS.mismatch(bMS);
296319
```
297320

321+
Vector API implementation:
322+
```java
323+
int i = 0;
324+
for (; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) {
325+
ByteVector va = ByteVector.fromArray(SPECIES_B, a, i);
326+
ByteVector vb = ByteVector.fromArray(SPECIES_B, b, i);
327+
var mask = va.compare(VectorOperators.NE, vb);
328+
if (mask.anyTrue()) {
329+
return i + mask.firstTrue();
330+
}
331+
}
332+
// omitting scalar cleanup
333+
return -1;
334+
```
335+
336+
The Vector API implementation is very similar to the one for `findI`: instead of comparing to the search
337+
element `e`, we compare to the value in the other array.
338+
298339
Running on an `x64 AVX512` and an `aarch64 NEON` machine, using arrays with `10000` elements:
299340

300341
<img width="500" alt="mismatch performance 10000" src="https://github.com/user-attachments/assets/420383ed-90ce-4823-9055-43bfe2f19377" />
@@ -303,6 +344,13 @@ And using arrays with `300` elements:
303344

304345
<img width="500" alt="mismatch performance 300" src="https://github.com/user-attachments/assets/59f6068a-cf67-432e-987f-5cdfac4b85f0" />
305346

347+
Observations:
348+
349+
- The reference implementation is not vectorized, but all others are.
350+
- The `Arrays::mismatch` and `MemorySegment::mismatch` implementation seem to be equally performant.
351+
- On `AVX512`, the Vector API implementation uses 512 bit (`zmm`) registers, but the `Arrays::mismatch` and `MemorySegment::mismatch` implementations only seem to use 256 bit (`ymm`) registers. Accordingly, the Vector API implementations is about 2x as fast.
352+
- On my `NEON` machine the Vector API implementation seems to be slightly slower than the `Arrays` and `MemorySegment` implementation - I have not yet investigated why.
353+
306354
**Algorithm 5: filter**
307355

308356
The previous algorithms were either element-wise, where all lanes were independent,

0 commit comments

Comments
 (0)