Skip to content

Commit

Permalink
add qualcomm 8cx gen 3 benchmark + minor tuning (#48)
Browse files Browse the repository at this point in the history
* simplify arm code

* some tuning

* adding qualcomm results
  • Loading branch information
lemire authored Jun 25, 2024
1 parent eb73315 commit bd4a55a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 9 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ faster than the standard library.
| Russian-Lipsum | 3.3 | 0.95 | 3.5 x |


On a Qualcomm 8cx gen3 (Windows Dev Kit 2023), we get roughly the same relative performance
boost as the Neoverse V1.

| data set | SimdUnicode speed (GB/s) | .NET speed (GB/s) | speed up |
|:----------------|:-----------|:--------------------------|:-------------------|
| Twitter.json | 15 | 10 | 1.5 x |
| Arabic-Lipsum | 4.0 | 2.3 | 1.7 x |
| Chinese-Lipsum | 4.0 | 2.9 | 1.4 x |
| Emoji-Lipsum | 4.0 | 0.9 | 4.4 x |
| Hebrew-Lipsum | 4.0 | 2.3 | 1.7 x |
| Hindi-Lipsum | 4.0 | 1.9 | 2.1 x |
| Japanese-Lipsum | 4.0 | 2.7  | 1.5 x |
| Korean-Lipsum | 4.0 | 1.5 | 2.7 x |
| Latin-Lipsum | 50 | 20 | 2.5 x |
| Russian-Lipsum | 4.0 | 1.2 | 3.3 x |

One difficulty with ARM processors is that they have varied SIMD/NEON performance. For example, Neoverse N1 processors, not to be confused with the Neoverse V1 design used by AWS Graviton 3, have weak SIMD performance. Of course, one can pick and choose which approach is best and it is not necessary to apply SimdUnicode is all cases. We expect good performance on recent ARM-based Qualcomm processors.

## Building the library
Expand Down
26 changes: 17 additions & 9 deletions src/UTF8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,20 +1388,28 @@ private unsafe static (int utfadjust, int scalaradjust) calculateErrorPathadjust
prevIncomplete = Vector128<byte>.Zero;
// Often, we have a lot of ASCII characters in a row.
int localasciirun = 16;
if (processedLength + localasciirun + 64 <= inputLength)
if (processedLength + localasciirun + 16 <= inputLength)
{
for (; processedLength + localasciirun + 64 <= inputLength; localasciirun += 64)
Vector128<byte> block = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun);
if (AdvSimd.Arm64.MaxAcross(Vector128.AsUInt32(AdvSimd.And(block, v80))).ToScalar() == 0)
{
Vector128<byte> block1 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun);
Vector128<byte> block2 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 16);
Vector128<byte> block3 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 32);
Vector128<byte> block4 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 48);
Vector128<byte> or = AdvSimd.Or(AdvSimd.Or(block1, block2), AdvSimd.Or(block3, block4));
if (AdvSimd.Arm64.MaxAcross(or).ToScalar() > 127)
localasciirun += 16;
for (; processedLength + localasciirun + 64 <= inputLength; localasciirun += 64)
{
break;
Vector128<byte> block1 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun);
Vector128<byte> block2 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 16);
Vector128<byte> block3 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 32);
Vector128<byte> block4 = AdvSimd.LoadVector128(pInputBuffer + processedLength + localasciirun + 48);
Vector128<byte> or = AdvSimd.Or(AdvSimd.Or(block1, block2), AdvSimd.Or(block3, block4));

if (AdvSimd.Arm64.MaxAcross(Vector128.AsUInt32(AdvSimd.And(or, v80))).ToScalar() != 0)
{
break;
}
}

}

processedLength += localasciirun - 16;
}
}
Expand Down

0 comments on commit bd4a55a

Please sign in to comment.