mathnet-numerics icon indicating copy to clipboard operation
mathnet-numerics copied to clipboard

Performance issue with LinearAlgebraControl.Provider.ScaleArray (MKL)

Open eoner opened this issue 2 years ago • 0 comments

I am trying to multiply a large Complex array with a scalar using the ScaleArray function of the LinearAlgebraControl class. The provider is {Intel MKL (x64; revision 15; MKL 2022.0)}. The ScaleArray call eventually calls the z_scale function of the libMathNetNumericsMKL.dll.

Compared to the simple loop implementation, MKL version is at least 2 times slower.

.NET loop average run time: 76,5 ms. Math.NET average run time: 170 ms.

Here is my test code:

class ScaleTest
{
	public static void Run()
	{
		MathNet.Numerics.Control.UseNativeMKL();

		int iterations = 100;

		var stopwatch = new Stopwatch();
		double averageTime = 0;

		var rand = new Random(0);
		var arr = Enumerable.Range(0, 10000000).Select(i => new Complex(rand.NextDouble(), rand.NextDouble())).ToArray();

		double scaleFactor = 0.2;

		//
		// with simple loop
		//
		stopwatch.Restart();
		for (int i = 0; i < iterations; i++)
		{
			var arr2 = arr.ToArray();
			ScaleWithLoop(arr2, scaleFactor);
		}
		stopwatch.Stop();

		averageTime = (double)stopwatch.ElapsedMilliseconds / iterations;
		Console.WriteLine($".NET loop average run time: {averageTime} ms.");

		//
		// with Math.NET LinearAlgebraProvider (MKL) ScaleArray
		//
		stopwatch.Restart();
		for (int i = 0; i < iterations; i++)
		{
			var arr2 = arr.ToArray();
			ScaleWithMKL(arr2, scaleFactor);
		}
		stopwatch.Stop();

		// Calculate the average run time in milliseconds
		averageTime = (double)stopwatch.ElapsedMilliseconds / iterations;
		Console.WriteLine($"Math.NET average run time: {averageTime} ms.");

	}


	/// <summary>
	/// Divides each element by the given scaleFactor IN-PLACE.
	/// </summary>
	/// <param name="arr"></param>
	/// <param name="scaleFactor"></param>
	public static void ScaleWithMKL(Complex[] arr, double scaleFactor)
	{
		Complex factor = 1.0 / scaleFactor;
		LinearAlgebraControl.Provider.ScaleArray(factor, arr, arr);
	}

	/// <summary>
	/// Divides each element by the given scaleFactor IN-PLACE.
	/// </summary>
	/// <param name="arr"></param>
	/// <param name="scaleFactor"></param>
	public static void ScaleWithLoop(Complex[] arr, double scaleFactor)
	{
		var factor = 1.0 / scaleFactor;
		int len = arr.Length;

		for (int i = 0; i < len; i++)
		{
			arr[i] = new Complex(factor * arr[i].Real, factor * arr[i].Imaginary);
		}
	}
}

eoner avatar Mar 22 '23 12:03 eoner