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://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
// obtaining a copy of this software and associated documentation
@ -138,7 +138,7 @@ namespace MathNet.Numerics
/// <summary>
/// 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>
/// <value>
/// <c>true</c> to use thread safe random number generators ; otherwise, <c>false</c>.
@ -148,7 +148,7 @@ namespace MathNet.Numerics
/// <summary>
/// Optional path to try to load native provider binaries from.
/// </summary>
public static DirectoryInfo NativeProviderPath { get; set; }
public static string NativeProviderPath { get; set; }
/// <summary>
/// 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.Runtime.InteropServices;
using System.Security;
using System.Threading;
#if NATIVE
@ -44,69 +45,29 @@ namespace MathNet.Numerics.Providers
/// </summary>
internal static class NativeProviderLoader
{
static Lazy<Dictionary<string, string>> _ArchitectureDirectories
= 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 readonly object StaticLock = new Object();
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>
/// Dictionary of handles to previously loaded libraries,
/// </summary>
static Dictionary<string, IntPtr> NativeHandles
{
get { return _nativeHandles.Value; }
}
static string _ArchDirectory = null;
static readonly Lazy<Dictionary<string, IntPtr>> NativeHandles = new Lazy<Dictionary<string, IntPtr>>(LazyThreadSafetyMode.PublicationOnly);
/// <summary>
/// Gets a string indicating the architecture and bitness of the current process.
/// </summary>
static string ArchDirectory
{
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;
}
static readonly Lazy<string> ArchitectureKey = new Lazy<string>(EvaluateArchitectureKey, LazyThreadSafetyMode.PublicationOnly);
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
{
@ -117,13 +78,40 @@ namespace MathNet.Numerics.Providers
}
}
/// <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 string EvaluateArchitectureKey()
{
if (IsUnix)
{
// 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>
/// 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
var userDir = Control.NativeProviderPath;
if (userDir != null && userDir.Exists && TryLoad(fileName, userDir))
if (TryLoad(fileName, Control.NativeProviderPath))
{
return true;
}
// Look under the current AppDomain's base directory
if (TryLoad(fileName, new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory)))
if (TryLoad(fileName, AppDomain.CurrentDomain.BaseDirectory))
{
return true;
}
// Look at this assembly's directory
var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (!string.IsNullOrEmpty(assemblyDir) && TryLoad(fileName, new DirectoryInfo(assemblyDir)))
if (TryLoad(fileName, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)))
{
return true;
}
@ -166,22 +152,24 @@ namespace MathNet.Numerics.Providers
/// and process mode if there is a matching subfolder.
/// </summary>
/// <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;
}
directory = Path.GetFullPath(directory);
// If we have a know architecture, try the matching subdirectory first
var architecture = ArchDirectory;
if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory.FullName, architecture, fileName))))
var architecture = ArchitectureKey.Value;
if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory, architecture, fileName))))
{
return true;
}
// 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>
@ -193,7 +181,7 @@ namespace MathNet.Numerics.Providers
lock (StaticLock)
{
IntPtr libraryHandle;
if (NativeHandles.TryGetValue(file.Name, out libraryHandle))
if (NativeHandles.Value.TryGetValue(file.Name, out libraryHandle))
{
return true;
}
@ -201,7 +189,7 @@ namespace MathNet.Numerics.Providers
if (!file.Exists)
{
// 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;
}
@ -216,7 +204,7 @@ namespace MathNet.Numerics.Providers
else
{
LastException = null;
NativeHandles[file.Name] = libraryHandle;
NativeHandles.Value[file.Name] = libraryHandle;
}
return libraryHandle != IntPtr.Zero;

Loading…
Cancel
Save