The software that I develop uses large floating-point arrays up to the maximum size that can be allocated in C#. I have a large number of algorithms such as convolutions and filters that get executed over those large arrays. I am currently updating as many algorithms as possible to fully threaded and vectorized.
By utilizing the System.Numerics.Vector<T>
methods, I am seeing typically a 300%+ performance improvement in many of the algorithms on computers equipped with AVX (where Vector<float>.Count
returns 4) and a 600%+ performance improvement in many of the algorithms on computers equipped with AVX2 (where Vector<float>.Count
returns 8).
NET Standard 2.1 System.Numerics.Vector<T>
here:
https://docs.microsoft.com/en-us/dotnet/api/system.numerics.vector-1?view=netstandard-2.1
One of the functions that I require on a number of the algorithms is to Clamp the array element value to a bounds Minimum or Maximum value after performing some mathematical operation on it. That is of course really easy to do with the single-threaded and multi-threaded algorithms that use standard arithmetic operations.
The issue that I am having is that System.Numerics.Vector<T>
doesn't include any kind of Clamp method (Vector2, 3, 4 do). So, for example, if I loop over a large array, modifying the array in Vector<float>.Count
chunks, I need to clamp each vector result to a min and/or max bounds prior to writing that vector-sized chunk back to the array.
I tried doing the Clamp in a loop on the array chunk data after the Vector operations, but the performance is abysmal. It is as slow or slower than simply doing the algorithm without vectorization.
Is there any way that I can conceivably improve the performance of this Clamp method?
This is some typical code of how I tried clamping. I fill the vector with a chunk of the array, perform some vector math, write the chunk back to the array, this is all nice and speedy, but then Clamping the array chunk in a loop after just kills the vectorization performance advantage.
int length = array.Length;
int floatcount = System.Numerics.Vector<float>.Count;
for (int i = 0; i < length; i += floatcount)
{
System.Numerics.Vector<float> arrayvector = new System.Numerics.Vector<float>(array, i);
arrayvector = System.Numerics.Vector.Multiply<float>(arrayvector, 2.0f);
// There may be different or multiple vector operations in here.
arrayvector.CopyTo(array, i);
// This is how I tried clamping the array data after the vector operation:
for (int j = 0; j < floatcount; j++)
{
if (array[i + j] > maximimum) { array[i + j] = maximimum; }
}
}
I'm probably being myopic and missing something really simple. That's what months of 16-hour programming days gets you. ;) Thanks for any insight.
Main
function? In questions about performance it's good when we could actually run and test it ourselves with a profiler or something - it'd be easier to compare the results and see whether the suggested improvement makes it really better ;-] \$\endgroup\$