///
/// This file is part of ILNumerics Community Edition.
///
/// ILNumerics Community Edition - high performance computing for applications.
/// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
///
/// ILNumerics Community Edition is free software: you can redistribute it and/or modify
/// it under the terms of the GNU General Public License version 3 as published by
/// the Free Software Foundation.
///
/// ILNumerics Community Edition is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with ILNumerics Community Edition. See the file License.txt in the root
/// of your distribution package. If not, see .
///
/// In addition this software uses the following components and/or licenses:
///
/// =================================================================================
/// The Open Toolkit Library License
///
/// Copyright (c) 2006 - 2009 the Open Toolkit library.
///
/// 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.
///
/// =================================================================================
///
using System;
using System.Configuration;
using ILNumerics.Misc;
namespace ILNumerics {
///
/// The class provides static setting properties to control the behaviour of ILNumerics, see Configuration in the online documentation
///
public class Settings {
static Settings() {
// Load the static cache values from the Defaul instance
// This enables the user to change default values via app.config
// and still provides a fast setting provider for internal functions.
LoadDefaults();
}
#region static local attributes
// local settings caches
internal static int s_minimumQuicksortLength;
internal static int s_maxNumberThreads;
internal static bool s_maxNumberThreadsConfigured;
internal static int s_minParallelElement3Count; // int.MaxValue; //
internal static int s_minParallelElement2Count; // int.MaxValue; //
internal static int s_minParallelElement1Count; // int.MaxValue; //
internal static int s_minElementLength4SystemArrayCopy;
internal static int s_maxSafeQuicksortRecursionDepth;
internal static int s_memoryPoolProfileMinLength;
internal static int s_memoryPoolProfileMaxLength;
internal static bool s_measurePerformanceAtRuntime;
internal static string s_memoryPoolProfileFileName; //"ILNumerics.MemoryPool.Profiler.txt";
internal static bool s_useThreadAffinity;
internal static bool s_allowInArrayAssignments;
internal static bool s_createRowVectorsByDefault;
internal static LogicalConversionMode s_logicalArrayToBoolConversion = LogicalConversionMode.NonScalarThrowsException;
#endregion
#region static global caches
///
/// Performance switch, dis-/allow direct assignments to input parameters - brings more efficient
/// memory management, default: true (safer, less efficient)
///
///
/// If this switch is set to 'false', you promise not to assign any values to input parameters
/// of type ILInArray, ILInCell or ILInLogical. This allows ILNumerics for more efficent
/// memory management, decreases the overall memory footprint of the application and enables certain
/// array operations to be automatically computed in-place. Depending on the specific algorithm
/// the performance profit may range from 1% up to even about 30%.
/// This switch should be set for the whole application globally. It is not recommended to change the state of
/// this switch once the application runs.
/// Since this switch targets the full application, all functions and modules involved must also follow
/// that contract! For all builtin functions of ILNumerics, compliance with this rule is garanteed. This means, if you are
/// not using any 3rd party algorithms and are able to make sure your own functions follow that scheme as well, it is safe
/// to set this switch to false and profit from faster execution times.
/// See the Optimizing Performance article in the online documentation.
public static bool AllowInArrayAssignments {
get {
return s_allowInArrayAssignments;
}
set {
s_allowInArrayAssignments = value;
}
}
///
/// Control layout of vectors when not specified explicitly.
///
/// -
/// true
/// When a vector is created without exlicitely specifying its shape, create a row vector
///
/// -
/// false (default)
/// When a vector is created without exlicitely specifying its shape, create a column vector
///
///
/// This setting affects the way ILNumerics handles the default shape for vectors created. One example is ,
/// where only the number of elements is given - but no size is specified. By default, ILNumerics will interpret the elements as targeting the first
/// dimension, ie. dimension #0. This will create a column vector. Setting this switch to 'true' will make ILNumerics to create a row vector in
/// such situations instead.
public static bool CreateRowVectorsByDefault {
get {
return s_createRowVectorsByDefault;
}
set {
s_createRowVectorsByDefault = value;
}
}
///
/// Upper limit of the range of array length to gather profiler information for
///
public static int MemoryPoolProfileMaxLength {
get {
return s_memoryPoolProfileMaxLength;
}
set {
s_memoryPoolProfileMaxLength = value;
}
}
///
/// Lower limit of the range of array length to gather profiler information for
///
public static int MemoryPoolProfileMinLength {
get {
return s_memoryPoolProfileMinLength;
}
set {
s_memoryPoolProfileMinLength = value;
}
}
///
/// If set to any non empty value, this setting triggers the memory pool profiler
///
/// Profiling the memory pool gives insights into those functions, which potentially
/// cause memory leaks in your application. It writes extensive stack trace information into the
/// logfile determined by this setting. It will contain the stack trace of any function, requesting
/// memory from the pool, which is never given back to the pool. Use this information in order to find and
/// correct those places - and increase stability and performance of your application. However,
/// make sure, this switch is cleared (or renamed) for production systems, since running the profiler
/// will diminish performance significantly.
public static string MemoryPoolProfileFileName {
get {
return s_memoryPoolProfileFileName;
}
set {
s_memoryPoolProfileFileName = value;
}
}
///
/// Gives the current setting for the reporting of runtime performance measures to the windows performance monitor (perfmon) (readonly)
///
/// Activating this switch requires administrative rights on each system the application is run - at least for the first time! This is
/// necessary in order to register the performance counters to the system. Afterwards, the application does not require administrative rights anymore.
/// Measuring the performance at runtime does not produce a substantial impact on the performance of your algorithm. However, due to the need for elevated rights
/// the feature is disabled by default. In order to enable it, a configuration variable named "ILNMeasurePerformanceAtRuntime" needs to be set in your
/// application configuration file.
public static bool MeasurePerformanceAtRuntime {
get { return s_measurePerformanceAtRuntime; }
}
///
/// Determine the minimum length for arrays to be sorted via Quicksort algorithm, smaller arrays are sorted via insertion sort
///
public static int MinimumQuicksortLength {
get { return s_minimumQuicksortLength; }
set { s_minimumQuicksortLength = value; }
}
///
/// Maximum number of threads for parallel execution of internal functions in ILNumerics
///
///
/// In order to maximize execution speed of numerical algorithms, the value of MaxNumberThreads should be equal to the number
/// of real processor cores on the system. For processors utilizing Hyper-threading the number on virtual cores
/// may be higher. However, since those virtual cores share certain ressources for execution, parallel utiliziation can not efficently be done with them. In this cases, the number of 'cores'
/// appearing e.g. in the windows task manager is misleading and the true number of independent cores should be used for MaxNumberThreads instead. Consult your proccessor vendor in order to find out, how many
/// independant cores your system utilizes.
/// Since the number of independent cores is not reliably determined by .NET, ILNumerics defaults to 2 cores on all multicore machines. Therefore, this setting should be set manually for
/// better processor utilization on multicore machines.
/// If your algorithm uses custom parallel execution models, it may
/// be necessary to set this value to '1'. ILNumerics will run single threaded than - leaving you the option to configure
/// the execution on parallel threads on your own.
/// The setting of this value also effects the corresponding value of any unmanaged optimized support library (e.g. MKL) internally used by ILNumerics.
///
public static int MaxNumberThreads {
get { return s_maxNumberThreads; }
set {
if (value < 1)
throw new ILNumerics.Exceptions.ILArgumentException("number of worker threads must be greater than 0");
Misc.ILThreadPool.Pool.MaxNumberThreads = value - 1;
s_maxNumberThreads = value;
}
}
///
/// Determine, if the current setting of is the result of a custom configuration
///
public static bool MaxNumberThreadsConfigured {
get { return s_maxNumberThreadsConfigured; }
private set { s_maxNumberThreadsConfigured = value; }
}
///
/// Threshold used to determine, if computations of O(n^3) built-in-functions are done in parallel on multicore machines
///
public static int MinParallelElement3Count {
get { return s_minParallelElement3Count; }
set { s_minParallelElement3Count = value; }
}
///
/// Threshold used to determine, if computations of O(n^2) built-in-functions are done in parallel on multicore machines
///
public static int MinParallelElement2Count {
get { return s_minParallelElement2Count; }
set { s_minParallelElement2Count = value; }
}
///
/// Threshold used to determine, if computations of O(n) built-in-functions are done in parallel on multicore machines
///
public static int MinParallelElement1Count {
get { return s_minParallelElement1Count; }
set { s_minParallelElement1Count = value; }
}
///
/// Maximal recursion depth the quicksort can go. default: 100 (for array length up to 2^100)
///
public static int MaxSafeQuicksortRecursionDepth {
get { return s_maxSafeQuicksortRecursionDepth; }
set { s_maxSafeQuicksortRecursionDepth = value; }
}
///
/// Controls implicit conversions from logical arrays to System.Boolean
///
/// This setting specifies, how logical arrays are converted to System.Boolean. Those
/// conversions are important, in order to simplify expressions like
/// if (A > B) { ... }
on arrays A and B.
/// Here, the comparison A > B
creates a logical array of the same size than A and B. The logical array contains
/// the result of the elementwise 'greater than' comparison. This setting here controls, how that logical is converted
/// to a System.Boolean, in order to evaluate the 'if' condition.
/// The default is LogicalConversionMode.NonScalarThrowsException, which would cause an exception to be thrown in
/// the example above. Only scalar logical arrays can be used in such implicit conversions than.
/// In order to further simplify the syntax, the LogicalConversionMode.ImplicitAllAll setting can be used. The above expression
/// would evaluate to true, if all elements of B are greater than corresponding elements of A. This settings therefore
/// eases the syntax for most situations. However, since most comparison operators comply to the underlying all rule,
/// the '!=' (not equal to) operator does not - at least to the extend of common intuition. In an expression:
/// if (A != B) { ... }
one would intuitively expect to execute the code block, if at least one element of A does not equal the corresponding element
/// of B. However, due to the all rule, this is not the case! In fact, the code would be executed only, if all elements would
/// evaluate to true. I.e. if no single pair of corresponding elements in A and B are equal. In order to
/// get the intuitively expected behavior, one would override this by:
/// if (ILMath.any(A != B)) { ... }
/// Since it may cause hard to find bugs, this setting should be used with care.
public static LogicalConversionMode LogicalArrayToBoolConversion {
get { return s_logicalArrayToBoolConversion; }
set { s_logicalArrayToBoolConversion = value; }
}
///
/// Determine, if main and worker threads should bind to constant cpus or not. The default is not to bind.
///
/// It usually is more efficient, to leave control of cpu binding to the runtime. However, if in certain situations, more control is required, this flag can
/// be used to make ILNumerics worker threads be affine to corresponding (native) threads.
public static bool UseThreadAffinity {
get { return s_useThreadAffinity; }
set { s_useThreadAffinity = value; }
}
#endregion
#region public interface
///
/// (Re)load settings from the application configuration file
///
public static void LoadDefaults() {
tryLoadSetting("ILNMinimumQuicksortLength", ref s_minimumQuicksortLength, int.Parse, 10);
if (!tryLoadSetting("ILNMaxNumberThreads", ref s_maxNumberThreads, int.Parse, 2)) {
// determine number of threads in another way: here: hardcoded
if (Environment.ProcessorCount > 1 && !System.Diagnostics.Debugger.IsAttached)
s_maxNumberThreads = 2;
else
s_maxNumberThreads = 1;
MaxNumberThreadsConfigured = false;
// TODO: try to determine number of PHYSICAL cores automatically
// try to load number of physical cores rather than logical cores - utilize CPUID via native function pointer!
} else {
MaxNumberThreadsConfigured = true;
}
tryLoadSetting("ILNMinParallelElement3Count", ref s_minParallelElement3Count, int.Parse, 500);
tryLoadSetting("ILNMinParallelElement2Count", ref s_minParallelElement2Count, int.Parse, 1000);
tryLoadSetting("ILNMinParallelElement1Count", ref s_minParallelElement1Count, int.Parse, (System.Environment.Is64BitProcess) ? 2000 : 2000);
tryLoadSetting("ILNMaxSafeQuicksortRecursionDepth", ref s_maxSafeQuicksortRecursionDepth, int.Parse, 100);
tryLoadSetting("ILNLogicalArrayToBoolConversion", ref s_logicalArrayToBoolConversion, logicalEnumParse, LogicalConversionMode.NonScalarThrowsException);
tryLoadSetting("ILNMemoryPoolProfileFileName", ref s_memoryPoolProfileFileName, dummyStringCopy, "");
tryLoadSetting("ILNMemoryPoolProfileMaxLength", ref s_memoryPoolProfileMaxLength, int.Parse, 500);
tryLoadSetting("ILNMemoryPoolProfileMinLength", ref s_memoryPoolProfileMinLength, int.Parse, 500);
tryLoadSetting("ILNMinElementLength4SystemArrayCopy", ref s_minElementLength4SystemArrayCopy, int.Parse, 50);
tryLoadSetting("ILNUseThreadAffinity", ref s_useThreadAffinity, bool.Parse, false);
tryLoadSetting("ILNCreateRowVectorsByDefault", ref s_createRowVectorsByDefault, bool.Parse, false);
tryLoadSetting("ILNAllowInArrayAssignments", ref s_allowInArrayAssignments, bool.Parse, true);
string configLicenseFilename = null, configLicenseResourceName = null;
tryLoadSetting("ILNLicenseFilename", ref configLicenseFilename, dummyStringCopy, "ILNumerics.lic");
tryLoadSetting("ILNLicenseResourceName", ref configLicenseResourceName, dummyStringCopy, "ILNumerics.lic");
tryLoadSetting("ILNMeasurePerformanceAtRuntime", ref s_measurePerformanceAtRuntime, bool.Parse, false);
}
#endregion
#region private helper
private static bool tryLoadSetting(string settingsName, ref T obj, System.Converter convert, T defaultValue) {
string value = System.Configuration.ConfigurationManager.AppSettings[settingsName];
T tmp;
if (!string.IsNullOrEmpty(value)) {
try {
tmp = convert(value); // may throws exception!
obj = tmp;
return true;
} catch (Exception exc) {
tmp = defaultValue;
throw new ILNumerics.Exceptions.ILArgumentException("Error reading default setting from application configuration, appsettings section: Invalid value for: '" + settingsName + "'", exc);
}
} else {
obj = defaultValue;
return false;
}
}
internal static string dummyStringCopy(string val) { return val.Trim(); }
internal static LogicalConversionMode logicalEnumParse(string val) {
LogicalConversionMode ret;
if (Enum.TryParse(val, out ret)) {
return ret;
}
throw new ILNumerics.Exceptions.ILArgumentException("The configuration value for 'ILNLogicalArrayToBoolConversion' is not valid.");
}
#endregion
}
}