diff --git a/src/Numerics.Tests/Providers/FourierTransform/FourierTransformProviderTests.cs b/src/Numerics.Tests/Providers/FourierTransform/FourierTransformProviderTests.cs index aab03ebc..6cd695cd 100644 --- a/src/Numerics.Tests/Providers/FourierTransform/FourierTransformProviderTests.cs +++ b/src/Numerics.Tests/Providers/FourierTransform/FourierTransformProviderTests.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // -// Copyright (c) 2009-2016 Math.NET +// Copyright (c) 2009-2018 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -42,6 +42,27 @@ namespace MathNet.Numerics.UnitTests.Providers.FourierTransform [TestFixture, Category("LAProvider")] public class FourierTransformProviderTests { + [Test] + public void ProviderSurvivesFreeResources() + { + var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2); + + var spectrum1 = new Complex[samples.Length]; + samples.Copy(spectrum1); + FourierTransformControl.Provider.Forward(spectrum1, FourierTransformScaling.ForwardScaling); + + FourierTransformControl.FreeResources(); + + var spectrum2 = new Complex[samples.Length]; + samples.Copy(spectrum2); + FourierTransformControl.Provider.Forward(spectrum2, FourierTransformScaling.ForwardScaling); + + for (var i = 0; i < spectrum1.Length; i++) + { + Assert.AreEqual(spectrum1[i], spectrum2[i]); + } + } + [Test] public void ForwardInplaceRealSine() { diff --git a/src/Numerics.Tests/Providers/LinearAlgebra/Double/LinearAlgebraProviderTests.cs b/src/Numerics.Tests/Providers/LinearAlgebra/Double/LinearAlgebraProviderTests.cs index c0c45253..6a5e95c3 100644 --- a/src/Numerics.Tests/Providers/LinearAlgebra/Double/LinearAlgebraProviderTests.cs +++ b/src/Numerics.Tests/Providers/LinearAlgebra/Double/LinearAlgebraProviderTests.cs @@ -72,6 +72,25 @@ namespace MathNet.Numerics.UnitTests.Providers.LinearAlgebra.Double { "Square1000x1000", (DenseMatrix)Matrix.Build.Random(1000, 1000, Dist) } }; + [Test] + public void ProviderSurvivesFreeResources() + { + var samples = Generate.PeriodicMap(16, w => Math.Sin(w), 16, 1.0, Constants.Pi2); + + var result1 = new double[samples.Length]; + LinearAlgebraControl.Provider.ScaleArray(2.5, samples, result1); + + LinearAlgebraControl.FreeResources(); + + var result2 = new double[samples.Length]; + LinearAlgebraControl.Provider.ScaleArray(2.5, samples, result2); + + for (var i = 0; i < result1.Length; i++) + { + Assert.AreEqual(result1[i], result2[i]); + } + } + /// /// Can add a vector to scaled vector /// diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 365e3b5a..5217cf6d 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -190,6 +190,12 @@ namespace MathNet.Numerics } #endif + public static void FreeResources() + { + LinearAlgebraControl.FreeResources(); + FourierTransformControl.FreeResources(); + } + public static void UseSingleThread() { _maxDegreeOfParallelism = 1; diff --git a/src/Numerics/Providers/Common/Cuda/CudaProvider.cs b/src/Numerics/Providers/Common/Cuda/CudaProvider.cs index 03fdde51..32511df1 100644 --- a/src/Numerics/Providers/Common/Cuda/CudaProvider.cs +++ b/src/Numerics/Providers/Common/Cuda/CudaProvider.cs @@ -113,6 +113,15 @@ namespace MathNet.Numerics.Providers.Common.Cuda return _nativeRevision; } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// This method is safe to call, even if the provider is not loaded. + /// + public static void FreeResources() + { + } + public static string Describe() { if (!_loaded) diff --git a/src/Numerics/Providers/Common/Mkl/MklProvider.cs b/src/Numerics/Providers/Common/Mkl/MklProvider.cs index bd81421a..acd3563c 100644 --- a/src/Numerics/Providers/Common/Mkl/MklProvider.cs +++ b/src/Numerics/Providers/Common/Mkl/MklProvider.cs @@ -154,6 +154,21 @@ namespace MathNet.Numerics.Providers.Common.Mkl } } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// This method is safe to call, even if the provider is not loaded. + /// + public static void FreeResources() + { + if (!_loaded) + { + return; + } + + FreeBuffers(); + } + /// /// Frees the memory allocated to the MKL memory pool. /// diff --git a/src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs b/src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs index 26de9406..971c6368 100644 --- a/src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs +++ b/src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs @@ -121,6 +121,15 @@ namespace MathNet.Numerics.Providers.Common.OpenBlas return _nativeRevision; } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// This method is safe to call, even if the provider is not loaded. + /// + public static void FreeResources() + { + } + internal static void ConfigureThreading() { if (!_loaded) diff --git a/src/Numerics/Providers/FourierTransform/FourierTransformControl.cs b/src/Numerics/Providers/FourierTransform/FourierTransformControl.cs index 9fc2c5ae..f6f9c347 100644 --- a/src/Numerics/Providers/FourierTransform/FourierTransformControl.cs +++ b/src/Numerics/Providers/FourierTransform/FourierTransformControl.cs @@ -170,6 +170,11 @@ namespace MathNet.Numerics.Providers.FourierTransform #endif } + public static void FreeResources() + { + Provider.FreeResources(); + } + static string GetCombinedHintPath() { if (!String.IsNullOrEmpty(HintPath)) diff --git a/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs index e9e46ef0..95f3c8ae 100644 --- a/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs @@ -52,6 +52,12 @@ namespace MathNet.Numerics.Providers.FourierTransform /// void InitializeVerify(); + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + void FreeResources(); + void Forward(Complex32[] samples, FourierTransformScaling scaling); void Forward(Complex[] samples, FourierTransformScaling scaling); void Backward(Complex32[] spectrum, FourierTransformScaling scaling); diff --git a/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs index b168d849..3ac171b3 100644 --- a/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs @@ -50,6 +50,14 @@ namespace MathNet.Numerics.Providers.FourierTransform { } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + public virtual void FreeResources() + { + } + public override string ToString() { return "Managed"; diff --git a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs index 48a6baeb..76d46861 100644 --- a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs @@ -87,9 +87,10 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl } /// - /// Frees the memory allocated to the MKL memory pool. + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. /// - internal void FreeBuffers() + public virtual void FreeResources() { Kernel kernel = Interlocked.Exchange(ref _kernel, null); if (kernel != null) @@ -97,7 +98,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl SafeNativeMethods.x_fft_free(ref kernel.Handle); } - MklProvider.FreeBuffers(); + MklProvider.FreeResources(); } public override string ToString() @@ -362,7 +363,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl public void Dispose() { - FreeBuffers(); + FreeResources(); } } } diff --git a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs index 7956c56d..ce61b778 100644 --- a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs @@ -84,6 +84,15 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda Solver(SafeNativeMethods.createSolverHandle(ref _solverHandle)); } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + public override void FreeResources() + { + CudaProvider.FreeResources(); + } + private void BLAS(int status) { switch (status) @@ -177,6 +186,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda { BLAS(SafeNativeMethods.destroyBLASHandle(_blasHandle)); Solver(SafeNativeMethods.destroySolverHandle(_solverHandle)); + FreeResources(); } } } diff --git a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs index e196ef86..3820eb1a 100644 --- a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2018 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -99,6 +99,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider /// void InitializeVerify(); + + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + void FreeResources(); } /// diff --git a/src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs b/src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs index f1d95e02..368d8bcc 100644 --- a/src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs +++ b/src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs @@ -28,6 +28,7 @@ // using System; +using System.Net; namespace MathNet.Numerics.Providers.LinearAlgebra { @@ -220,6 +221,11 @@ namespace MathNet.Numerics.Providers.LinearAlgebra #endif } + public static void FreeResources() + { + Provider.FreeResources(); + } + static string GetCombinedHintPath() { if (!String.IsNullOrEmpty(HintPath)) diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs index fd7a81c9..44a009af 100644 --- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs @@ -70,6 +70,14 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + public virtual void FreeResources() + { + } + public override string ToString() { return "Managed"; diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs index 600150bd..1798f2e9 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs @@ -48,7 +48,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// /// Intel's Math Kernel Library (MKL) linear algebra provider. /// - internal partial class MklLinearAlgebraProvider : ManagedLinearAlgebraProvider + internal partial class MklLinearAlgebraProvider : ManagedLinearAlgebraProvider, IDisposable { const int _minimumCompatibleRevision = 4; @@ -112,10 +112,24 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + public override void FreeResources() + { + MklProvider.FreeResources(); + } + public override string ToString() { return MklProvider.Describe(); } + + public void Dispose() + { + FreeResources(); + } } } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs index 301d40b2..86b64ab3 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs @@ -55,7 +55,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// /// OpenBLAS linear algebra provider. /// - internal partial class OpenBlasLinearAlgebraProvider : ManagedLinearAlgebraProvider + internal partial class OpenBlasLinearAlgebraProvider : ManagedLinearAlgebraProvider, IDisposable { const int _minimumCompatibleRevision = 1; @@ -97,10 +97,24 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas } } + /// + /// Frees memory buffers, caches and handles allocated in or to the provider. + /// Does not unload the provider itself, it is still usable afterwards. + /// + public override void FreeResources() + { + OpenBlasProvider.FreeResources(); + } + public override string ToString() { return OpenBlasProvider.Describe(); } + + public void Dispose() + { + FreeResources(); + } } }