Browse Source

Native Provider Loader: code simplification

cuda
Christoph Ruegg 12 years ago
parent
commit
4967e057b4
  1. 6
      src/Numerics/Control.cs
  2. 132
      src/Numerics/Providers/NativeProviderLoader.cs

6
src/Numerics/Control.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2014 Math.NET // Copyright (c) 2009-2015 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -138,7 +138,7 @@ namespace MathNet.Numerics
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to use thread safe random number generators (RNG). /// Gets or sets a value indicating whether to use thread safe random number generators (RNG).
/// Thread safe RNG about two and half time slower than non-thread safe RNG. /// Thread safe RNG about two and half time slower than non-thread safe RNG.
/// </summary> /// </summary>
/// <value> /// <value>
/// <c>true</c> to use thread safe random number generators ; otherwise, <c>false</c>. /// <c>true</c> to use thread safe random number generators ; otherwise, <c>false</c>.
@ -148,7 +148,7 @@ namespace MathNet.Numerics
/// <summary> /// <summary>
/// Optional path to try to load native provider binaries from. /// Optional path to try to load native provider binaries from.
/// </summary> /// </summary>
public static DirectoryInfo NativeProviderPath { get; set; } public static string NativeProviderPath { get; set; }
/// <summary> /// <summary>
/// Gets or sets the linear algebra provider. Consider to use UseNativeMKL or UseManaged instead. /// Gets or sets the linear algebra provider. Consider to use UseNativeMKL or UseManaged instead.

132
src/Numerics/Providers/NativeProviderLoader.cs

@ -34,6 +34,7 @@ using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
using System.Threading;
#if NATIVE #if NATIVE
@ -44,69 +45,29 @@ namespace MathNet.Numerics.Providers
/// </summary> /// </summary>
internal static class NativeProviderLoader internal static class NativeProviderLoader
{ {
static Lazy<Dictionary<string, string>> _ArchitectureDirectories static readonly object StaticLock = new Object();
= new Lazy<Dictionary<string, string>>(
() => new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "x86", "x86" },
{ "AMD64", "x64" },
{ "IA64", "ia64" },
{ "ARM", "arm" }
},
true);
/// <summary>
/// Default directories for each architecture.
/// </summary>
static Dictionary<string, string> ArchitectureDirectories
{
get { return _ArchitectureDirectories.Value; }
}
static Lazy<Dictionary<string, IntPtr>> _nativeHandles = new Lazy<Dictionary<string, IntPtr>>(true); const string X86 = "x86";
const string X64 = "x64";
const string IA64 = "ia64";
const string ARM = "arm";
const string ARM64 = "arm64";
/// <summary> /// <summary>
/// Dictionary of handles to previously loaded libraries, /// Dictionary of handles to previously loaded libraries,
/// </summary> /// </summary>
static Dictionary<string, IntPtr> NativeHandles static readonly Lazy<Dictionary<string, IntPtr>> NativeHandles = new Lazy<Dictionary<string, IntPtr>>(LazyThreadSafetyMode.PublicationOnly);
{
get { return _nativeHandles.Value; }
}
static string _ArchDirectory = null;
/// <summary> /// <summary>
/// Gets a string indicating the architecture and bitness of the current process. /// Gets a string indicating the architecture and bitness of the current process.
/// </summary> /// </summary>
static string ArchDirectory static readonly Lazy<string> ArchitectureKey = new Lazy<string>(EvaluateArchitectureKey, LazyThreadSafetyMode.PublicationOnly);
{
get
{
if (string.IsNullOrEmpty(_ArchDirectory))
{
string architecture;
if (IsUnix)
{
// Only support x86 and amd64 on Unix as there isn't a reliable way to detect the architecture
architecture = Environment.Is64BitProcess ? "AMD64" : "x86";
}
else
{
architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
if (!Environment.Is64BitProcess && string.Equals(architecture, "AMD64", StringComparison.OrdinalIgnoreCase))
{
architecture = "x86";
}
}
// Fallback to using the architecture name if unknown
if (!ArchitectureDirectories.TryGetValue(architecture, out _ArchDirectory))
_ArchDirectory = architecture;
}
return _ArchDirectory; /// <summary>
} /// If the last native library failed to load then gets the corresponding exception
} /// which occurred or null if the library was successfully loaded.
/// </summary>
public static Exception LastException { get; private set; }
static bool IsUnix static bool IsUnix
{ {
@ -117,13 +78,40 @@ namespace MathNet.Numerics.Providers
} }
} }
/// <summary> static string EvaluateArchitectureKey()
/// If the last native library failed to load then gets the corresponding exception {
/// which occurred or null if the library was successfully loaded. if (IsUnix)
/// </summary> {
public static Exception LastException { get; private set; } // Only support x86 and amd64 on Unix as there isn't a reliable way to detect the architecture
return Environment.Is64BitProcess ? X64 : X86;
}
static readonly object StaticLock = new Object(); var architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
if (string.Equals(architecture, "x86", StringComparison.OrdinalIgnoreCase))
{
return X86;
}
if (string.Equals(architecture, "amd64", StringComparison.OrdinalIgnoreCase)
|| string.Equals(architecture, "x64", StringComparison.OrdinalIgnoreCase))
{
return Environment.Is64BitProcess ? X64 : X86;
}
if (string.Equals(architecture, "ia64", StringComparison.OrdinalIgnoreCase))
{
return IA64;
}
if (string.Equals(architecture, "arm", StringComparison.OrdinalIgnoreCase))
{
return Environment.Is64BitProcess ? ARM64 : ARM;
}
// Fallback if unknown
return architecture;
}
/// <summary> /// <summary>
/// Load the native library with the given filename. /// Load the native library with the given filename.
@ -138,21 +126,19 @@ namespace MathNet.Numerics.Providers
} }
// If we have an extra path provided by the user, look there first // If we have an extra path provided by the user, look there first
var userDir = Control.NativeProviderPath; if (TryLoad(fileName, Control.NativeProviderPath))
if (userDir != null && userDir.Exists && TryLoad(fileName, userDir))
{ {
return true; return true;
} }
// Look under the current AppDomain's base directory // Look under the current AppDomain's base directory
if (TryLoad(fileName, new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory))) if (TryLoad(fileName, AppDomain.CurrentDomain.BaseDirectory))
{ {
return true; return true;
} }
// Look at this assembly's directory // Look at this assembly's directory
var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (TryLoad(fileName, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)))
if (!string.IsNullOrEmpty(assemblyDir) && TryLoad(fileName, new DirectoryInfo(assemblyDir)))
{ {
return true; return true;
} }
@ -166,22 +152,24 @@ namespace MathNet.Numerics.Providers
/// and process mode if there is a matching subfolder. /// and process mode if there is a matching subfolder.
/// </summary> /// </summary>
/// <returns>True if the library was successfully loaded or if it has already been loaded.</returns> /// <returns>True if the library was successfully loaded or if it has already been loaded.</returns>
public static bool TryLoad(string fileName, DirectoryInfo directory) public static bool TryLoad(string fileName, string directory)
{ {
if (!directory.Exists) if (!Directory.Exists(directory))
{ {
return false; return false;
} }
directory = Path.GetFullPath(directory);
// If we have a know architecture, try the matching subdirectory first // If we have a know architecture, try the matching subdirectory first
var architecture = ArchDirectory; var architecture = ArchitectureKey.Value;
if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory.FullName, architecture, fileName)))) if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory, architecture, fileName))))
{ {
return true; return true;
} }
// Otherwise try to load directly from the provided directory // Otherwise try to load directly from the provided directory
return TryLoadFile(new FileInfo(Path.Combine(directory.FullName, fileName))); return TryLoadFile(new FileInfo(Path.Combine(directory, fileName)));
} }
/// <summary> /// <summary>
@ -193,7 +181,7 @@ namespace MathNet.Numerics.Providers
lock (StaticLock) lock (StaticLock)
{ {
IntPtr libraryHandle; IntPtr libraryHandle;
if (NativeHandles.TryGetValue(file.Name, out libraryHandle)) if (NativeHandles.Value.TryGetValue(file.Name, out libraryHandle))
{ {
return true; return true;
} }
@ -201,7 +189,7 @@ namespace MathNet.Numerics.Providers
if (!file.Exists) if (!file.Exists)
{ {
// If the library isn't found within an architecture specific folder then return false // If the library isn't found within an architecture specific folder then return false
// to allow normal P/Invoke searching behaviour when the library is called // to allow normal P/Invoke searching behavior when the library is called
return false; return false;
} }
@ -216,7 +204,7 @@ namespace MathNet.Numerics.Providers
else else
{ {
LastException = null; LastException = null;
NativeHandles[file.Name] = libraryHandle; NativeHandles.Value[file.Name] = libraryHandle;
} }
return libraryHandle != IntPtr.Zero; return libraryHandle != IntPtr.Zero;

Loading…
Cancel
Save