From 89aa96eec8e44806e4012b010c3778ae00502a5e Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Tue, 17 May 2011 20:35:58 +0800 Subject: [PATCH] started optimizing the parallel code for small matrices and vectors --- .../ManagedLinearAlgebraProvider.Complex.cs | 20 +++--- .../ManagedLinearAlgebraProvider.Complex32.cs | 20 +++--- .../ManagedLinearAlgebraProvider.Double.cs | 20 +++--- .../ManagedLinearAlgebraProvider.Single.cs | 29 ++++---- src/Numerics/Control.cs | 24 +++++++ src/Numerics/Threading/CommonParallel.cs | 66 +++++++++++++++---- 6 files changed, 125 insertions(+), 54 deletions(-) diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs index 14f65dab..2176bafd 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs @@ -67,15 +67,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha.IsZero()) { - CommonParallel.For(0, y.Length, index => result[index] = y[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index]); } else if (alpha.IsOne()) { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + x[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + x[index]); } else { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + (alpha * x[index])); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + (alpha * x[index])); } } @@ -95,15 +95,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha.IsZero()) { - CommonParallel.For(0, x.Length, index => result[index] = Complex.Zero); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = Complex.Zero); } else if (alpha.IsOne()) { - CommonParallel.For(0, x.Length, index => result[index] = x[index]); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = x[index]); } else { - CommonParallel.For(0, x.Length, index => { result[index] = alpha * x[index]; }); + CommonParallel.ElementFor(0, x.Length, x.Length, index => { result[index] = alpha * x[index]; }); } } @@ -172,7 +172,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -207,7 +207,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -242,7 +242,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] * y[i]); } /// @@ -277,7 +277,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] / y[index]; }); } /// diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs index 005f9c82..4e733e21 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs @@ -61,15 +61,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha.IsZero()) { - CommonParallel.For(0, y.Length, index => result[index] = y[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index]); } else if (alpha.IsOne()) { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + x[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + x[index]); } else { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + (alpha * x[index])); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + (alpha * x[index])); } } @@ -89,15 +89,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha.IsZero()) { - CommonParallel.For(0, x.Length, index => result[index] = Complex32.Zero); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = Complex32.Zero); } else if (alpha.IsOne()) { - CommonParallel.For(0, x.Length, index => result[index] = x[index]); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = x[index]); } else { - CommonParallel.For(0, x.Length, index => { result[index] = alpha * x[index]; }); + CommonParallel.ElementFor(0, x.Length, x.Length, index => { result[index] = alpha * x[index]; }); } } @@ -167,7 +167,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -202,7 +202,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -237,7 +237,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] * y[i]); } /// @@ -272,7 +272,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] / y[index]; }); } /// diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs index f2f3b822..b1bcceb8 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs @@ -61,15 +61,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 0.0) { - CommonParallel.For(0, y.Length, index => result[index] = y[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index]); } else if (alpha == 1.0) { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + x[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + x[index]); } else { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + (alpha * x[index])); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + (alpha * x[index])); } } @@ -89,15 +89,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 0.0) { - CommonParallel.For(0, x.Length, index => result[index] = 0.0); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = 0.0); } else if (alpha == 1.0) { - CommonParallel.For(0, x.Length, index => result[index] = x[index]); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = x[index]); } else { - CommonParallel.For(0, x.Length, index => { result[index] = alpha * x[index]; }); + CommonParallel.ElementFor(0, x.Length, x.Length, index => { result[index] = alpha * x[index]; }); } } @@ -167,7 +167,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] + y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] + y[index]; }); } /// @@ -202,7 +202,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] - y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] - y[index]; }); } /// @@ -237,7 +237,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] * y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] * y[index]; }); } /// @@ -272,7 +272,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] / y[index]; }); } /// diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs index 820c6de2..369c491a 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs @@ -61,15 +61,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 0.0) { - CommonParallel.For(0, y.Length, index => result[index] = y[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index]); } else if (alpha == 1.0) { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + x[index]); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + x[index]); } else { - CommonParallel.For(0, y.Length, index => result[index] = y[index] + (alpha * x[index])); + CommonParallel.ElementFor(0, y.Length, y.Length, index => result[index] = y[index] + (alpha * x[index])); } } @@ -89,15 +89,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 0.0) { - CommonParallel.For(0, x.Length, index => result[index] = 0.0f); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = 0.0f); } else if (alpha == 1.0) { - CommonParallel.For(0, x.Length, index => result[index] = x[index]); + CommonParallel.ElementFor(0, x.Length, x.Length, index => result[index] = x[index]); } else { - CommonParallel.For(0, x.Length, index => { result[index] = alpha * x[index]; }); + CommonParallel.ElementFor(0, x.Length, x.Length, index => { result[index] = alpha * x[index]; }); } } @@ -125,8 +125,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - float sum = 0; - CommonParallel.For(0, y.Length, index => sum += y[index] * x[index]); + var sum = 0.0f; + + for (var index = 0; index < y.Length; index++) + { + sum += y[index] * x[index]; + } + return sum; } @@ -162,7 +167,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -197,7 +202,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -232,7 +237,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.ElementFor(0, y.Length, y.Length, i => result[i] = x[i] * y[i]); } /// @@ -267,7 +272,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; }); + CommonParallel.ElementFor(0, y.Length, y.Length, index => { result[index] = x[index] / y[index]; }); } /// diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 7bd8e51f..b56c6c74 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -56,6 +56,11 @@ namespace MathNet.Numerics /// private static int _parallelizeOrder = 64; + /// + /// The default cutoff point for order size for the matrix multiply in linear algebra provider. + /// + private static int _parallelizeElements = 256; + /// /// Initializes static members of the Control class. /// @@ -161,5 +166,24 @@ namespace MathNet.Numerics } } + /// + /// Gets or sets the number of elements a vector or matrix must contain before we multiply threads. + /// + /// Number of elements. Default is 256. + public static int ParallelizeElements + { + get + { + return _parallelizeElements; + } + + set + { + if (_parallelizeElements > 2) + { + _parallelizeElements = value; + } + } + } } } diff --git a/src/Numerics/Threading/CommonParallel.cs b/src/Numerics/Threading/CommonParallel.cs index 954d016e..595a4da7 100644 --- a/src/Numerics/Threading/CommonParallel.cs +++ b/src/Numerics/Threading/CommonParallel.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2011 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -31,7 +31,6 @@ namespace MathNet.Numerics.Threading { using System; - using System.Numerics; #if !SILVERLIGHT using System.Collections.Concurrent; @@ -43,6 +42,26 @@ namespace MathNet.Numerics.Threading /// public static class CommonParallel { + /// + /// Executes a for loop in which iterations may run in parallel. + /// + /// The start index, inclusive. + /// The end index, exclusive. + /// The number of elements that will be iterated over. + /// The body to be invoked for each iteration. + /// The argument is null. + /// At least one invocation of the body threw an exception. + public static void ElementFor(int fromInclusive, int toExclusive, int numberOfElements, Action body) + { + var parallel = true; + if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2 || numberOfElements < Control.ParallelizeElements) + { + parallel = false; + } + + For(fromInclusive, toExclusive, body, parallel); + } + /// /// Executes a for loop in which iterations may run in parallel. /// @@ -53,21 +72,37 @@ namespace MathNet.Numerics.Threading /// At least one invocation of the body threw an exception. public static void For(int fromInclusive, int toExclusive, Action body) { -#if SILVERLIGHT - Parallel.For(fromInclusive, toExclusive, body); -#else + var parallel = true; if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) { - for (var index = fromInclusive; index < toExclusive; index++) - { - body(index); - } + parallel = false; } - else + + For(fromInclusive, toExclusive, body, parallel); + } + + /// + /// Executes a for loop in which iterations may run in parallel. + /// + /// The start index, inclusive. + /// The end index, exclusive. + /// The body to be invoked for each iteration. + /// Use multiple threads. + /// The argument is null. + /// At least one invocation of the body threw an exception. + public static void For(int fromInclusive, int toExclusive, Action body, bool parallel) + { + if (parallel) { +#if SILVERLIGHT + Parallel.For(fromInclusive, toExclusive, body); +#else Parallel.ForEach( Partitioner.Create(fromInclusive, toExclusive), - new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, + new ParallelOptions + { + MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads + }, (range, loopState) => { for (var i = range.Item1; i < range.Item2; i++) @@ -75,8 +110,15 @@ namespace MathNet.Numerics.Threading body(i); } }); - } #endif + } + else + { + for (var index = fromInclusive; index < toExclusive; index++) + { + body(index); + } + } } /* ///