// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2020 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. // #if NATIVE using System; using System.Collections.Generic; namespace IStation.Numerics.Providers.Common.Mkl { public static class MklProvider { const int DesignTimeRevision = 14; const int MinimumCompatibleRevision = 4; static int _nativeRevision; static Version _mklVersion; static bool _nativeX86; static bool _nativeX64; static bool _nativeIA64; static bool _loaded; public static bool IsAvailable(string hintPath = null) { if (_loaded) { return true; } if (AppSwitches.DisableNativeProviders || AppSwitches.DisableMklNativeProvider) { return false; } try { if (!NativeProviderLoader.TryLoad(SafeNativeMethods.DllName, hintPath)) { return false; } int a = SafeNativeMethods.query_capability(0); int b = SafeNativeMethods.query_capability(1); int nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision); return a == 0 && b == -1 && nativeRevision >= MinimumCompatibleRevision; } catch { return false; } } /// Revision public static int Load(string hintPath = null) { return Load(hintPath, MklConsistency.Auto, MklPrecision.Double, MklAccuracy.High); } /// Revision [CLSCompliant(false)] public static int Load( string hintPath = null, MklConsistency consistency = MklConsistency.Auto, MklPrecision precision = MklPrecision.Double, MklAccuracy accuracy = MklAccuracy.High) { if (_loaded) { return _nativeRevision; } if (AppSwitches.DisableNativeProviders || AppSwitches.DisableMklNativeProvider) { throw new NotSupportedException("MKL Native Provider support is actively disabled by AppSwitches."); } int a, b; try { NativeProviderLoader.TryLoad(SafeNativeMethods.DllName, hintPath); a = SafeNativeMethods.query_capability(0); b = SafeNativeMethods.query_capability(1); _nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision); _nativeX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0; _nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0; _nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0; // 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); } _mklVersion = new Version( SafeNativeMethods.query_capability((int)ProviderConfig.MklMajorVersion), SafeNativeMethods.query_capability((int)ProviderConfig.MklMinorVersion), SafeNativeMethods.query_capability((int)ProviderConfig.MklUpdateVersion)); } catch (DllNotFoundException e) { throw new NotSupportedException("MKL Native Provider not found.", e); } catch (BadImageFormatException e) { throw new NotSupportedException("MKL Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e); } catch (EntryPointNotFoundException e) { throw new NotSupportedException("MKL Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e); } if (a != 0 || b != -1 || _nativeRevision < MinimumCompatibleRevision) { throw new NotSupportedException("MKL Native Provider too old. Consider upgrading to a newer version."); } _loaded = true; 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() { if (!_loaded) { return; } FreeBuffers(); } /// /// Frees the memory allocated to the MKL memory pool. /// public static void FreeBuffers() { if (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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 (!_loaded) { throw new InvalidOperationException(); } 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() { if (!_loaded) { return "Intel MKL (not loaded)"; } var parts = new List(); if (_nativeX86) parts.Add("x86"); if (_nativeX64) parts.Add("x64"); if (_nativeIA64) parts.Add("IA64"); parts.Add("revision " + _nativeRevision); if (_nativeRevision > DesignTimeRevision) parts.Add("ahead revision " + DesignTimeRevision); if (_nativeRevision < DesignTimeRevision) parts.Add("behind revision " + DesignTimeRevision); if (_mklVersion.Major > 0) { parts.Add(_mklVersion.Build == 0 ? string.Concat("MKL ", _mklVersion.ToString(2)) : string.Concat("MKL ", _mklVersion.ToString(2), " Update ", _mklVersion.Build)); } return string.Concat("Intel MKL (", string.Join("; ", parts.ToArray()), ")"); } 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 } } } #endif