From fdc773a71efe06b38230b140f9768334c5ef9316 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Thu, 14 May 2015 18:50:38 +0200 Subject: [PATCH] Native: automatically use native provider if available #314, new Control.TryXY alternatives Control.TryUseNativeMKL() etc as an alternative way to use a specific provider if it is available, but you're not interested in why if not. Control.TryUseNative() tries to use any known native provider in an undefined (but reasonable) order. Changed the default behavior to try to load any known native provider available automatically instead of falling back to managed straight away. Added basic inline-xml docs --- src/Numerics/Control.cs | 130 ++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 24 deletions(-) diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 9ccd07e4..f8475fd2 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -30,7 +30,6 @@ using MathNet.Numerics.Providers.LinearAlgebra; using System; -using System.IO; using System.Threading.Tasks; namespace MathNet.Numerics @@ -40,6 +39,8 @@ namespace MathNet.Numerics /// public static class Control { + const string EnvVarLAProvider = "MathNetNumericsLAProvider"; + static int _maxDegreeOfParallelism; static int _blockSize; static int _parallelizeOrder; @@ -70,63 +71,58 @@ namespace MathNet.Numerics #else try { - const string name = "MathNetNumericsLAProvider"; - var value = Environment.GetEnvironmentVariable(name); + var value = Environment.GetEnvironmentVariable(EnvVarLAProvider); switch (value != null ? value.ToUpperInvariant() : string.Empty) { #if NATIVE case "MKL": - LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(); + UseNativeMKL(); break; case "CUDA": - LinearAlgebraProvider = new Providers.LinearAlgebra.Cuda.CudaLinearAlgebraProvider(); + UseNativeCUDA(); break; case "OPENBLAS": - LinearAlgebraProvider = new Providers.LinearAlgebra.OpenBlas.OpenBlasLinearAlgebraProvider(); + UseNativeOpenBLAS(); break; #endif default: - LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); + if (!TryUseNative()) + { + UseManaged(); + } break; } } catch { // We don't care about any failures here at all (because "auto") - LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); + UseManaged(); } #endif } - public static void UseSingleThread() - { - _maxDegreeOfParallelism = 1; - ThreadSafeRandomNumberGenerators = false; - - LinearAlgebraProvider.InitializeVerify(); - } - - public static void UseMultiThreading() - { - _maxDegreeOfParallelism = Environment.ProcessorCount; - ThreadSafeRandomNumberGenerators = true; - - LinearAlgebraProvider.InitializeVerify(); - } - public static void UseManaged() { LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); } #if NATIVE + + /// + /// Use the Intel MKL native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeMKL() { LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(); } + /// + /// 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.LinearAlgebra.Mkl.MklConsistency consistency = Providers.LinearAlgebra.Mkl.MklConsistency.Auto, @@ -136,17 +132,103 @@ namespace MathNet.Numerics LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(consistency, precision, accuracy); } + /// + /// Try to use the Intel MKL native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeMKL() + { + return Try(UseNativeMKL); + } + + /// + /// Use the Nvidia CUDA native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeCUDA() { LinearAlgebraProvider = new Providers.LinearAlgebra.Cuda.CudaLinearAlgebraProvider(); } + /// + /// Try to use the Nvidia CUDA native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeCUDA() + { + return Try(UseNativeCUDA); + } + + /// + /// Use the OpenBLAS native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeOpenBLAS() { LinearAlgebraProvider = new Providers.LinearAlgebra.OpenBlas.OpenBlasLinearAlgebraProvider(); } + + /// + /// Try to use the OpenBLAS native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeOpenBLAS() + { + return Try(UseNativeOpenBLAS); + } + + /// + /// Try to use any available native provider in an undefined order. + /// + /// + /// True if one of the native providers was found and successfully initialized. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNative() + { + return TryUseNativeCUDA() || TryUseNativeMKL() || TryUseNativeOpenBLAS(); + } + + static bool Try(Action action) + { + try + { + action(); + return true; + } + catch + { + // intentionally swallow exceptions here - use the non-try variants if you're interested in why + return false; + } + } #endif + public static void UseSingleThread() + { + _maxDegreeOfParallelism = 1; + ThreadSafeRandomNumberGenerators = false; + + LinearAlgebraProvider.InitializeVerify(); + } + + public static void UseMultiThreading() + { + _maxDegreeOfParallelism = Environment.ProcessorCount; + ThreadSafeRandomNumberGenerators = true; + + LinearAlgebraProvider.InitializeVerify(); + } + /// /// Gets or sets a value indicating whether the distribution classes check validate each parameter. /// For the multivariate distributions this could involve an expensive matrix factorization.