Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/benchmarks/micro/MicroBenchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<NoWarn>$(NoWarn);CS8002</NoWarn>
<!-- Suppress binaryformatter obsolete warning -->
<NoWarn>$(NoWarn);SYSLIB0011</NoWarn>
<!-- Suppress Sve experimental feature warning -->
<NoWarn>$(NoWarn);SYSLIB5003</NoWarn>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>portable</DebugType>
Expand Down
163 changes: 75 additions & 88 deletions src/benchmarks/micro/sve/Partition.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable SYSLIB5003

using System;
using System.Numerics;
using System.Runtime.Intrinsics;
Expand Down Expand Up @@ -74,131 +72,120 @@ public unsafe ulong Scalar()
[Benchmark]
public unsafe ulong SvePartition()
{
if (Sve.IsSupported)
fixed (uint* input = _input, left = _left, right = _right)
{
fixed (uint* input = _input, left = _left, right = _right)
{
long i = 0;
long i = 0;

ulong indexLeft = 0;
ulong indexRight = 0;
ulong indexLeft = 0;
ulong indexRight = 0;

Vector<uint> ones = Vector<uint>.One;
Vector<uint> ones = Vector<uint>.One;

Vector<uint> firstElemVec = Sve.DuplicateSelectedScalarToVector(
Sve.LoadVector(Sve.CreateTrueMaskUInt32(), input), 0
);
Vector<uint> firstElemVec = Sve.DuplicateSelectedScalarToVector(
Sve.LoadVector(Sve.CreateTrueMaskUInt32(), input), 0
);

// Create a predicate for the loop.
Vector<uint> pLoop = Sve.CreateWhileLessThanMask32Bit(i, Size);
// Create a predicate for the loop.
Vector<uint> pLoop = Sve.CreateWhileLessThanMask32Bit(i, Size);

while (Sve.TestAnyTrue(Sve.CreateTrueMaskUInt32(), pLoop))
{
// Load from the input array based on the loop predicate.
Vector<uint> data = Sve.LoadVector(pLoop, input + i);

// Predicate for elements in input array less than the first element.
Vector<uint> pCompare = Sve.CompareLessThan(data, firstElemVec);
while (Sve.TestAnyTrue(Sve.CreateTrueMaskUInt32(), pLoop))
{
// Load from the input array based on the loop predicate.
Vector<uint> data = Sve.LoadVector(pLoop, input + i);

// Apply the pLoop mask.
Vector<uint> pInner = Sve.ConditionalSelect(pLoop, pCompare, Vector<uint>.Zero);
// Predicate for elements in input array less than the first element.
Vector<uint> pCompare = Sve.CompareLessThan(data, firstElemVec);

// Squash all found elements to the lower lanes of the vector.
Vector<uint> compacted = Sve.Compact(pInner, data);
// Apply the pLoop mask.
Vector<uint> pInner = Sve.ConditionalSelect(pLoop, pCompare, Vector<uint>.Zero);

// Store the squashed elements to the first output array.
// (This uses the loop predicate, so some additional zeros may be stored).
Sve.StoreAndZip(pLoop, left + indexLeft, compacted);
// Squash all found elements to the lower lanes of the vector.
Vector<uint> compacted = Sve.Compact(pInner, data);

// Increment the position in the first output array by the number of elements found.
indexLeft = Sve.SaturatingIncrementByActiveElementCount(indexLeft, pInner);
// Store the squashed elements to the first output array.
// (This uses the loop predicate, so some additional zeros may be stored).
Sve.StoreAndZip(pLoop, left + indexLeft, compacted);

// Find all elements in input array NOT less than the first element.
// (Flip the pCompare predicate by XORing with ones)
pInner = Sve.ConditionalSelect(pLoop, Sve.Xor(pCompare, ones), Vector<uint>.Zero);
// Increment the position in the first output array by the number of elements found.
indexLeft = Sve.SaturatingIncrementByActiveElementCount(indexLeft, pInner);

// Repeat for the right array.
compacted = Sve.Compact(pInner, data);
Sve.StoreAndZip(pLoop, right + indexRight, compacted);
indexRight = Sve.SaturatingIncrementByActiveElementCount(indexRight, pInner);
// Find all elements in input array NOT less than the first element.
// (Flip the pCompare predicate by XORing with ones)
pInner = Sve.ConditionalSelect(pLoop, Sve.Xor(pCompare, ones), Vector<uint>.Zero);

i = Sve.SaturatingIncrementBy32BitElementCount(i, 1);
pLoop = Sve.CreateWhileLessThanMask32Bit(i, Size);
}
// Repeat for the right array.
compacted = Sve.Compact(pInner, data);
Sve.StoreAndZip(pLoop, right + indexRight, compacted);
indexRight = Sve.SaturatingIncrementByActiveElementCount(indexRight, pInner);

return indexRight;
i = Sve.SaturatingIncrementBy32BitElementCount(i, 1);
pLoop = Sve.CreateWhileLessThanMask32Bit(i, Size);
}

return indexRight;
}
return 0;
}

[Benchmark]
public unsafe ulong SveTail()
{
if (Sve.IsSupported)
fixed (uint* input = _input, left = _left, right = _right)
{
fixed (uint* input = _input, left = _left, right = _right)
{
long i = 0;
long i = 0;

ulong indexLeft = 0;
ulong indexRight = 0;
ulong indexLeft = 0;
ulong indexRight = 0;

Vector<uint> firstElemVec = Sve.DuplicateSelectedScalarToVector(
Sve.LoadVector(Sve.CreateTrueMaskUInt32(), input), 0
);
Vector<uint> firstElemVec = Sve.DuplicateSelectedScalarToVector(
Sve.LoadVector(Sve.CreateTrueMaskUInt32(), input), 0
);

Vector<uint> pTrue = Sve.CreateTrueMaskUInt32();
Vector<uint> pTrue = Sve.CreateTrueMaskUInt32();

while (i < (Size - (int)Sve.Count32BitElements()))
{
Vector<uint> data = Sve.LoadVector(pTrue, input + i);
while (i < (Size - (int)Sve.Count32BitElements()))
{
Vector<uint> data = Sve.LoadVector(pTrue, input + i);

// Predicate for elements in input array less than the first element.
Vector<uint> pInner = Sve.CompareLessThan(data, firstElemVec);
// Predicate for elements in input array less than the first element.
Vector<uint> pInner = Sve.CompareLessThan(data, firstElemVec);

// Squash all found elements to the lower lanes of the vector.
Vector<uint> compacted = Sve.Compact(pInner, data);
// Squash all found elements to the lower lanes of the vector.
Vector<uint> compacted = Sve.Compact(pInner, data);

// Store the squashed elements to the first output array.
Sve.StoreAndZip(pTrue, left + indexLeft, compacted);
// Store the squashed elements to the first output array.
Sve.StoreAndZip(pTrue, left + indexLeft, compacted);

// Increment the position in the first output array by the number of elements found.
indexLeft = Sve.SaturatingIncrementByActiveElementCount(indexLeft, pInner);
// Increment the position in the first output array by the number of elements found.
indexLeft = Sve.SaturatingIncrementByActiveElementCount(indexLeft, pInner);

// Find elements greater than or equal to the first element.
pInner = Sve.CompareGreaterThanOrEqual(data, firstElemVec);
// Find elements greater than or equal to the first element.
pInner = Sve.CompareGreaterThanOrEqual(data, firstElemVec);

// Repeat for the right array.
compacted = Sve.Compact(pInner, data);
Sve.StoreAndZip(pTrue, right + indexRight, compacted);
indexRight = Sve.SaturatingIncrementByActiveElementCount(indexRight, pInner);
// Repeat for the right array.
compacted = Sve.Compact(pInner, data);
Sve.StoreAndZip(pTrue, right + indexRight, compacted);
indexRight = Sve.SaturatingIncrementByActiveElementCount(indexRight, pInner);

i = Sve.SaturatingIncrementBy32BitElementCount(i, 1);
}
i = Sve.SaturatingIncrementBy32BitElementCount(i, 1);
}

// Handler remaining elements.
for (; i < Size; i++)
// Handler remaining elements.
for (; i < Size; i++)
{
if (input[i] < input[0])
{
if (input[i] < input[0])
{
left[indexLeft] = input[i];
indexLeft++;
}
else
{
right[indexRight] = input[i];
indexRight++;
}
left[indexLeft] = input[i];
indexLeft++;
}
else
{
right[indexRight] = input[i];
indexRight++;
}

return indexRight;
}

return indexRight;
}
return 0;
}
}
}

#pragma warning restore SYSLIB5003
123 changes: 55 additions & 68 deletions src/benchmarks/micro/sve/StrCmp.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable SYSLIB5003

using System;
using System.Numerics;
using System.Linq;
Expand Down Expand Up @@ -118,106 +116,95 @@ public int Vector128StrCmp()
[Benchmark]
public unsafe long SveStrCmp()
{
if (Sve.IsSupported)
{
int i = 0;
int elemsInVector = (int)Sve.Count8BitElements();
int i = 0;
int elemsInVector = (int)Sve.Count8BitElements();

Vector<byte> ptrue = Sve.CreateTrueMaskByte();
Vector<byte> pLoop = (Vector<byte>)Sve.CreateWhileLessThanMask8Bit(i, Size);
Vector<byte> cmp = Vector<byte>.Zero;
Vector<byte> arr1_data, arr2_data;
Vector<byte> ptrue = Sve.CreateTrueMaskByte();
Vector<byte> pLoop = (Vector<byte>)Sve.CreateWhileLessThanMask8Bit(i, Size);
Vector<byte> cmp = Vector<byte>.Zero;
Vector<byte> arr1_data, arr2_data;

if (_arr1.Length == _arr2.Length)
if (_arr1.Length == _arr2.Length)
{
fixed (byte* arr1_ptr = _arr1, arr2_ptr = _arr2)
{
fixed (byte* arr1_ptr = _arr1, arr2_ptr = _arr2)
while (Sve.TestFirstTrue(ptrue, pLoop))
{
while (Sve.TestFirstTrue(ptrue, pLoop))
{
arr1_data = Sve.LoadVector(pLoop, arr1_ptr + i);
arr2_data = Sve.LoadVector(pLoop, arr2_ptr + i);
arr1_data = Sve.LoadVector(pLoop, arr1_ptr + i);
arr2_data = Sve.LoadVector(pLoop, arr2_ptr + i);

// stop if any values arent equal
cmp = Sve.CompareNotEqualTo(arr1_data, arr2_data);
// stop if any values arent equal
cmp = Sve.CompareNotEqualTo(arr1_data, arr2_data);

if (Sve.TestAnyTrue(ptrue, cmp))
break;
if (Sve.TestAnyTrue(ptrue, cmp))
break;

i += elemsInVector;
i += elemsInVector;

pLoop = (Vector<byte>)Sve.CreateWhileLessThanMask8Bit(i, Size);
}
pLoop = (Vector<byte>)Sve.CreateWhileLessThanMask8Bit(i, Size);
}

// create a bitmask to find position of changed value
int mask = 0;
for (int j = 0; j < elemsInVector; j++)
{
// set bits in lanes with non zero elements
if (cmp.GetElement(j) != 0)
mask |= (1 << j);
}
// create a bitmask to find position of changed value
int mask = 0;
for (int j = 0; j < elemsInVector; j++)
{
// set bits in lanes with non zero elements
if (cmp.GetElement(j) != 0)
mask |= (1 << j);
}

int zeroCount = BitOperations.TrailingZeroCount(mask);
int zeroCount = BitOperations.TrailingZeroCount(mask);

if (zeroCount < elemsInVector)
return _arr1[i + zeroCount] - _arr2[i + zeroCount];
if (zeroCount < elemsInVector)
return _arr1[i + zeroCount] - _arr2[i + zeroCount];

return 0;
}
return 0;
}

Debug.Assert(false, "Different array lengths are not expected");
return 0;
}

Debug.Assert(false, "Different array lengths are not expected");
return 0;
}

[Benchmark]
public unsafe long SveTail()
{
if (Sve.IsSupported)
{
Vector<byte> ptrue = Sve.CreateTrueMaskByte();
Vector<byte> cmp;
Vector<byte> arr1_data, arr2_data;
Vector<byte> ptrue = Sve.CreateTrueMaskByte();
Vector<byte> cmp;
Vector<byte> arr1_data, arr2_data;

int i = 0;
int elemsInVector = (int)Sve.Count8BitElements();
int i = 0;
int elemsInVector = (int)Sve.Count8BitElements();

if (_arr1.Length == _arr2.Length)
if (_arr1.Length == _arr2.Length)
{
fixed (byte* arr1_ptr = _arr1, arr2_ptr = _arr2)
{
fixed (byte* arr1_ptr = _arr1, arr2_ptr = _arr2)
for (; i <= Size - elemsInVector; i += elemsInVector)
{
for (; i <= Size - elemsInVector; i += elemsInVector)
{
arr1_data = Sve.LoadVector(ptrue, arr1_ptr + i);
arr2_data = Sve.LoadVector(ptrue, arr2_ptr + i);
arr1_data = Sve.LoadVector(ptrue, arr1_ptr + i);
arr2_data = Sve.LoadVector(ptrue, arr2_ptr + i);

cmp = Sve.CompareNotEqualTo(arr1_data, arr2_data);

if (Sve.TestAnyTrue(ptrue, cmp))
{
break;
}
}
cmp = Sve.CompareNotEqualTo(arr1_data, arr2_data);

for (; i < Size; i++)
if (Sve.TestAnyTrue(ptrue, cmp))
{
if (_arr1[i] != _arr2[i])
return _arr1[i] - _arr2[i];
break;
}
}

return 0;
for (; i < Size; i++)
{
if (_arr1[i] != _arr2[i])
return _arr1[i] - _arr2[i];
}
}

Debug.Assert(false, "Different array lengths are not expected");
return 0;
return 0;
}
}

Debug.Assert(false, "Different array lengths are not expected");
return 0;
}
}
}

#pragma warning restore SYSLIB5003
Loading
Loading