From d7440d51259bb03004b329051921b20938c0e55c Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sat, 8 Oct 2016 10:02:30 +0200 Subject: [PATCH] FFT: MKL provider refactoring due to sharing between FFT and LA - 2 --- src/Numerics/Control.cs | 15 ++ src/Numerics/Numerics.csproj | 1 + .../Providers/Common/Mkl/MklProvider.cs | 139 ++++++++++++++++++ .../Common/Mkl/MklProviderCapabilities.cs | 2 +- .../Common/Mkl/MklProviderPrecision.cs | 66 +++++++++ .../Mkl/MklFourierTransformProvider.cs | 60 ++++++++ .../LinearAlgebra/ILinearAlgebraProvider.cs | 12 +- .../Mkl/MklLinearAlgebraProvider.cs | 119 +++++---------- 8 files changed, 323 insertions(+), 91 deletions(-) create mode 100644 src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index dfd8fe32..4045a7d4 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -135,6 +135,7 @@ namespace MathNet.Numerics /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. /// [CLSCompliant(false)] + [Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")] public static void UseNativeMKL( Providers.LinearAlgebra.Mkl.MklConsistency consistency = Providers.LinearAlgebra.Mkl.MklConsistency.Auto, Providers.LinearAlgebra.Mkl.MklPrecision precision = Providers.LinearAlgebra.Mkl.MklPrecision.Double, @@ -144,6 +145,20 @@ namespace MathNet.Numerics FourierTransformProvider = new Providers.FourierTransform.Mkl.MklFourierTransformProvider(); } + /// + /// Use the Intel MKL native provider for linear algebra, with the specified configuration parameters. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// + [CLSCompliant(false)] + public static void UseNativeMKL( + Providers.Common.Mkl.MklConsistency consistency = Providers.Common.Mkl.MklConsistency.Auto, + Providers.Common.Mkl.MklPrecision precision = Providers.Common.Mkl.MklPrecision.Double, + Providers.Common.Mkl.MklAccuracy accuracy = Providers.Common.Mkl.MklAccuracy.High) + { + LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(consistency, precision, accuracy); + FourierTransformProvider = new Providers.FourierTransform.Mkl.MklFourierTransformProvider(); + } + /// /// Try to use the Intel MKL native provider for linear algebra. /// diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 06febca7..842ae7c9 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -173,6 +173,7 @@ Resources.resx + diff --git a/src/Numerics/Providers/Common/Mkl/MklProvider.cs b/src/Numerics/Providers/Common/Mkl/MklProvider.cs index c096513c..86618320 100644 --- a/src/Numerics/Providers/Common/Mkl/MklProvider.cs +++ b/src/Numerics/Providers/Common/Mkl/MklProvider.cs @@ -72,6 +72,122 @@ namespace MathNet.Numerics.Providers.Common.Mkl { throw new NotSupportedException("MKL Native Provider too old. Consider upgrading to a newer version."); } + + ConfigureThreading(); + } + + static void ConfigureThreading() + { + // set threading settings, if supported + if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0) + { + SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism); + } + } + + public static void ConfigurePrecision(MklConsistency consistency, MklPrecision precision, MklAccuracy accuracy) + { + // set numerical consistency, precision and accuracy modes, if supported + if (SafeNativeMethods.query_capability((int)ProviderConfig.Precision) > 0) + { + SafeNativeMethods.set_consistency_mode((int)consistency); + SafeNativeMethods.set_vml_mode((uint)precision | (uint)accuracy); + } + } + + /// + /// Frees the memory allocated to the MKL memory pool. + /// + public static void FreeBuffers() + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + SafeNativeMethods.free_buffers(); + } + + /// + /// Frees the memory allocated to the MKL memory pool on the current thread. + /// + public static void ThreadFreeBuffers() + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + SafeNativeMethods.thread_free_buffers(); + } + + /// + /// Disable the MKL memory pool. May impact performance. + /// + public static void DisableMemoryPool() + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + SafeNativeMethods.disable_fast_mm(); + } + + /// + /// Retrieves information about the MKL memory pool. + /// + /// On output, returns the number of memory buffers allocated. + /// Returns the number of bytes allocated to all memory buffers. + public static long MemoryStatistics(out int allocatedBuffers) + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + return SafeNativeMethods.mem_stat(out allocatedBuffers); + } + + /// + /// Enable gathering of peak memory statistics of the MKL memory pool. + /// + public static void EnablePeakMemoryStatistics() + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Enable); + } + + /// + /// Disable gathering of peak memory statistics of the MKL memory pool. + /// + public static void DisablePeakMemoryStatistics() + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Disable); + } + + /// + /// Measures peak memory usage of the MKL memory pool. + /// + /// Whether the usage counter should be reset. + /// The peak number of bytes allocated to all memory buffers. + public static long PeakMemoryStatistics(bool reset = true) + { + if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) + { + throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); + } + + return SafeNativeMethods.peak_mem_usage((int)(reset ? MklMemoryRequestMode.PeakMemoryReset : MklMemoryRequestMode.PeakMemory)); } public static string Describe() @@ -80,5 +196,28 @@ namespace MathNet.Numerics.Providers.Common.Mkl _nativeRevision, _nativeX86 ? "x86" : _nativeX64 ? "x64" : _nativeIA64 ? "IA64" : "unknown"); } + + enum MklMemoryRequestMode : int + { + /// + /// Disable gathering memory usage + /// + Disable = 0, + + /// + /// Enable gathering memory usage + /// + Enable = 1, + + /// + /// Return peak memory usage + /// + PeakMemory = 2, + + /// + /// Return peak memory usage and reset counter + /// + PeakMemoryReset = -1 + } } } diff --git a/src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs b/src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs index b1676a65..908c04a2 100644 --- a/src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs +++ b/src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // -// Copyright (c) 2009-2015 Math.NET +// Copyright (c) 2009-2016 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation diff --git a/src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs b/src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs new file mode 100644 index 00000000..45c5ed6c --- /dev/null +++ b/src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs @@ -0,0 +1,66 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// +// Copyright (c) 2009-2016 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace MathNet.Numerics.Providers.Common.Mkl +{ + /// + /// Consistency vs. performance trade-off between runs on different machines. + /// + public enum MklConsistency : int + { + /// Consistent on the same CPU only (maximum performance) + Auto = 2, + /// Consistent on Intel and compatible CPUs with SSE2 support (maximum compatibility) + Compatible = 3, + /// Consistent on Intel CPUs supporting SSE2 or later + SSE2 = 4, + /// Consistent on Intel CPUs supporting SSE4.2 or later + SSE4_2 = 8, + /// Consistent on Intel CPUs supporting AVX or later + AVX = 9, + /// Consistent on Intel CPUs supporting AVX2 or later + AVX2 = 10 + } + + [CLSCompliant(false)] + public enum MklAccuracy : uint + { + Low = 0x1, + High = 0x2 + } + + [CLSCompliant(false)] + public enum MklPrecision : uint + { + Single = 0x10, + Double = 0x20 + } +} diff --git a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs index 50c08ab3..afb9ac74 100644 --- a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs @@ -49,6 +49,66 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl } } + /// + /// Frees the memory allocated to the MKL memory pool. + /// + public void FreeBuffers() + { + MklProvider.FreeBuffers(); + } + + /// + /// Frees the memory allocated to the MKL memory pool on the current thread. + /// + public void ThreadFreeBuffers() + { + MklProvider.ThreadFreeBuffers(); + } + + /// + /// Disable the MKL memory pool. May impact performance. + /// + public void DisableMemoryPool() + { + MklProvider.DisableMemoryPool(); + } + + /// + /// Retrieves information about the MKL memory pool. + /// + /// On output, returns the number of memory buffers allocated. + /// Returns the number of bytes allocated to all memory buffers. + public long MemoryStatistics(out int allocatedBuffers) + { + return MklProvider.MemoryStatistics(out allocatedBuffers); + } + + /// + /// Enable gathering of peak memory statistics of the MKL memory pool. + /// + public void EnablePeakMemoryStatistics() + { + MklProvider.EnablePeakMemoryStatistics(); + } + + /// + /// Disable gathering of peak memory statistics of the MKL memory pool. + /// + public void DisablePeakMemoryStatistics() + { + MklProvider.DisablePeakMemoryStatistics(); + } + + /// + /// Measures peak memory usage of the MKL memory pool. + /// + /// Whether the usage counter should be reset. + /// The peak number of bytes allocated to all memory buffers. + public long PeakMemoryStatistics(bool reset = true) + { + return MklProvider.PeakMemoryStatistics(reset); + } + public override string ToString() { return MklProvider.Describe(); diff --git a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs index 57ed0707..2298581a 100644 --- a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs @@ -2,9 +2,9 @@ // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics -// +// // Copyright (c) 2009-2013 Math.NET -// +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -13,10 +13,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -151,7 +151,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra T DotProduct(T[] x, T[] y); /// - /// Does a point wise add of two arrays z = x + y. This can be used + /// Does a point wise add of two arrays z = x + y. This can be used /// to add vectors or matrices. /// /// The array x. @@ -163,7 +163,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra void AddArrays(T[] x, T[] y, T[] result); /// - /// Does a point wise subtraction of two arrays z = x - y. This can be used + /// Does a point wise subtraction of two arrays z = x - y. This can be used /// to subtract vectors or matrices. /// /// The array x. diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs index a107839a..92f7a316 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs @@ -49,6 +49,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// /// Consistency vs. performance trade-off between runs on different machines. /// + [Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")] public enum MklConsistency : int { /// Consistent on the same CPU only (maximum performance) @@ -66,6 +67,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } [CLSCompliant(false)] + [Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")] public enum MklAccuracy : uint { Low = 0x1, @@ -73,43 +75,21 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } [CLSCompliant(false)] + [Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")] public enum MklPrecision : uint { Single = 0x10, Double = 0x20 } - internal enum MklMemoryRequestMode : int - { - /// - /// Disable gathering memory usage - /// - Disable = 0, - - /// - /// Enable gathering memory usage - /// - Enable = 1, - - /// - /// Return peak memory usage - /// - PeakMemory = 2, - - /// - /// Return peak memory usage and reset counter - /// - PeakMemoryReset = -1 - } - /// /// Intel's Math Kernel Library (MKL) linear algebra provider. /// public partial class MklLinearAlgebraProvider : ManagedLinearAlgebraProvider { - readonly MklConsistency _consistency; - readonly MklPrecision _precision; - readonly MklAccuracy _accuracy; + readonly Common.Mkl.MklConsistency _consistency; + readonly Common.Mkl.MklPrecision _precision; + readonly Common.Mkl.MklAccuracy _accuracy; /// /// Sets the desired bit consistency on repeated identical computations on varying CPU architectures, @@ -118,10 +98,28 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// VML optimal precision and rounding. /// VML accuracy mode. [CLSCompliant(false)] + [Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")] public MklLinearAlgebraProvider( MklConsistency consistency = MklConsistency.Auto, MklPrecision precision = MklPrecision.Double, MklAccuracy accuracy = MklAccuracy.High) + { + _consistency = (Common.Mkl.MklConsistency)consistency; + _precision = (Common.Mkl.MklPrecision)precision; + _accuracy = (Common.Mkl.MklAccuracy)accuracy; + } + + /// + /// Sets the desired bit consistency on repeated identical computations on varying CPU architectures, + /// as a trade-off with performance. + /// + /// VML optimal precision and rounding. + /// VML accuracy mode. + [CLSCompliant(false)] + public MklLinearAlgebraProvider( + Common.Mkl.MklConsistency consistency = Common.Mkl.MklConsistency.Auto, + Common.Mkl.MklPrecision precision = Common.Mkl.MklPrecision.Double, + Common.Mkl.MklAccuracy accuracy = Common.Mkl.MklAccuracy.High) { _consistency = consistency; _precision = precision; @@ -130,9 +128,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl public MklLinearAlgebraProvider() { - _consistency = MklConsistency.Auto; - _precision = MklPrecision.Double; - _accuracy = MklAccuracy.High; + _consistency = Common.Mkl.MklConsistency.Auto; + _precision = Common.Mkl.MklPrecision.Double; + _accuracy = Common.Mkl.MklAccuracy.High; } /// @@ -142,6 +140,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl public override void InitializeVerify() { MklProvider.Load(minRevision: 4); + MklProvider.ConfigurePrecision(_consistency, _precision, _accuracy); int linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebraMajor); @@ -150,19 +149,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl { throw new NotSupportedException(string.Format("MKL Native Provider not compatible. Expecting linear algebra v2 but provider implements v{0}.", linearAlgebra)); } - - // set numerical consistency, precision and accuracy modes, if supported - if (SafeNativeMethods.query_capability((int)ProviderConfig.Precision) > 0) - { - SafeNativeMethods.set_consistency_mode((int)_consistency); - SafeNativeMethods.set_vml_mode((uint)_precision | (uint)_accuracy); - } - - // set threading settings, if supported - if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0) - { - SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism); - } } /// @@ -170,12 +156,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// public void FreeBuffers() { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - SafeNativeMethods.free_buffers(); + MklProvider.FreeBuffers(); } /// @@ -183,12 +164,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// public void ThreadFreeBuffers() { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - SafeNativeMethods.thread_free_buffers(); + MklProvider.ThreadFreeBuffers(); } /// @@ -196,12 +172,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// public void DisableMemoryPool() { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - SafeNativeMethods.disable_fast_mm(); + MklProvider.DisableMemoryPool(); } /// @@ -211,12 +182,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// Returns the number of bytes allocated to all memory buffers. public long MemoryStatistics(out int allocatedBuffers) { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - return SafeNativeMethods.mem_stat(out allocatedBuffers); + return MklProvider.MemoryStatistics(out allocatedBuffers); } /// @@ -224,12 +190,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// public void EnablePeakMemoryStatistics() { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Enable); + MklProvider.EnablePeakMemoryStatistics(); } /// @@ -237,12 +198,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// public void DisablePeakMemoryStatistics() { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Disable); + MklProvider.DisablePeakMemoryStatistics(); } /// @@ -252,12 +208,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// The peak number of bytes allocated to all memory buffers. public long PeakMemoryStatistics(bool reset = true) { - if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1) - { - throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version."); - } - - return SafeNativeMethods.peak_mem_usage((int)(reset ? MklMemoryRequestMode.PeakMemoryReset : MklMemoryRequestMode.PeakMemory)); + return MklProvider.PeakMemoryStatistics(reset); } public override string ToString()