1 | ///
|
---|
2 | /// This file is part of ILNumerics Community Edition.
|
---|
3 | ///
|
---|
4 | /// ILNumerics Community Edition - high performance computing for applications.
|
---|
5 | /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
|
---|
6 | ///
|
---|
7 | /// ILNumerics Community Edition is free software: you can redistribute it and/or modify
|
---|
8 | /// it under the terms of the GNU General Public License version 3 as published by
|
---|
9 | /// the Free Software Foundation.
|
---|
10 | ///
|
---|
11 | /// ILNumerics Community Edition is distributed in the hope that it will be useful,
|
---|
12 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | /// GNU General Public License for more details.
|
---|
15 | ///
|
---|
16 | /// You should have received a copy of the GNU General Public License
|
---|
17 | /// along with ILNumerics Community Edition. See the file License.txt in the root
|
---|
18 | /// of your distribution package. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | ///
|
---|
20 | /// In addition this software uses the following components and/or licenses:
|
---|
21 | ///
|
---|
22 | /// =================================================================================
|
---|
23 | /// The Open Toolkit Library License
|
---|
24 | ///
|
---|
25 | /// Copyright (c) 2006 - 2009 the Open Toolkit library.
|
---|
26 | ///
|
---|
27 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
|
---|
28 | /// of this software and associated documentation files (the "Software"), to deal
|
---|
29 | /// in the Software without restriction, including without limitation the rights to
|
---|
30 | /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
---|
31 | /// the Software, and to permit persons to whom the Software is furnished to do
|
---|
32 | /// so, subject to the following conditions:
|
---|
33 | ///
|
---|
34 | /// The above copyright notice and this permission notice shall be included in all
|
---|
35 | /// copies or substantial portions of the Software.
|
---|
36 | ///
|
---|
37 | /// =================================================================================
|
---|
38 | ///
|
---|
39 |
|
---|
40 | using System;
|
---|
41 | using System.Configuration;
|
---|
42 | using ILNumerics.Misc;
|
---|
43 |
|
---|
44 | namespace ILNumerics {
|
---|
45 |
|
---|
46 | /// <summary>
|
---|
47 | /// The class provides static setting properties to control the behaviour of ILNumerics, see <a href="http://ilnumerics.net/$Configuration.html">Configuration</a> in the online documentation
|
---|
48 | /// </summary>
|
---|
49 | public class Settings {
|
---|
50 |
|
---|
51 | static Settings() {
|
---|
52 | // Load the static cache values from the Defaul instance
|
---|
53 | // This enables the user to change default values via app.config
|
---|
54 | // and still provides a fast setting provider for internal functions.
|
---|
55 | LoadDefaults();
|
---|
56 | }
|
---|
57 |
|
---|
58 | #region static local attributes
|
---|
59 | // local settings caches
|
---|
60 | internal static int s_minimumQuicksortLength;
|
---|
61 | internal static int s_maxNumberThreads;
|
---|
62 | internal static bool s_maxNumberThreadsConfigured;
|
---|
63 | internal static int s_minParallelElement3Count; // int.MaxValue; //
|
---|
64 | internal static int s_minParallelElement2Count; // int.MaxValue; //
|
---|
65 | internal static int s_minParallelElement1Count; // int.MaxValue; //
|
---|
66 | internal static int s_minElementLength4SystemArrayCopy;
|
---|
67 | internal static int s_maxSafeQuicksortRecursionDepth;
|
---|
68 | internal static int s_memoryPoolProfileMinLength;
|
---|
69 | internal static int s_memoryPoolProfileMaxLength;
|
---|
70 | internal static bool s_measurePerformanceAtRuntime;
|
---|
71 | internal static string s_memoryPoolProfileFileName; //"ILNumerics.MemoryPool.Profiler.txt";
|
---|
72 | internal static bool s_useThreadAffinity;
|
---|
73 | internal static bool s_allowInArrayAssignments;
|
---|
74 | internal static bool s_createRowVectorsByDefault;
|
---|
75 | internal static LogicalConversionMode s_logicalArrayToBoolConversion = LogicalConversionMode.NonScalarThrowsException;
|
---|
76 |
|
---|
77 | #endregion
|
---|
78 |
|
---|
79 | #region static global caches
|
---|
80 | /// <summary>
|
---|
81 | /// Performance switch, dis-/allow direct assignments to input parameters - brings more efficient
|
---|
82 | /// memory management, default: true (safer, less efficient)
|
---|
83 | /// </summary>
|
---|
84 | /// <remarks>
|
---|
85 | /// <para>If this switch is set to 'false', you promise not to assign any values to input parameters
|
---|
86 | /// of type <c>ILInArray</c>, <c>ILInCell</c> or <c>ILInLogical</c>. This allows ILNumerics for more efficent
|
---|
87 | /// memory management, decreases the overall memory footprint of the application and enables certain
|
---|
88 | /// array operations to be automatically computed in-place. Depending on the specific algorithm
|
---|
89 | /// the performance profit may range from 1% up to even about 30%.</para>
|
---|
90 | /// This switch should be set for the whole application globally. It is not recommended to change the state of
|
---|
91 | /// this switch once the application runs.
|
---|
92 | /// <para>Since this switch targets the full application, all functions and modules involved must also follow
|
---|
93 | /// that contract! For all builtin functions of ILNumerics, compliance with this rule is garanteed. This means, if you are
|
---|
94 | /// not using any 3rd party algorithms and are able to make sure your own functions follow that scheme as well, it is safe
|
---|
95 | /// to set this switch to <c>false</c> and profit from faster execution times.</para>
|
---|
96 | /// <para>See the <a href="http://ilnumerics.net/$PerfMemoryOpt.html">Optimizing Performance</a> article in the online documentation.</para></remarks>
|
---|
97 | public static bool AllowInArrayAssignments {
|
---|
98 | get {
|
---|
99 | return s_allowInArrayAssignments;
|
---|
100 | }
|
---|
101 | set {
|
---|
102 | s_allowInArrayAssignments = value;
|
---|
103 | }
|
---|
104 | }
|
---|
105 |
|
---|
106 | /// <summary>
|
---|
107 | /// Control layout of vectors when not specified explicitly.
|
---|
108 | /// <list type="bullet">
|
---|
109 | /// <item>
|
---|
110 | /// <term>true</term>
|
---|
111 | /// <description>When a vector is created without exlicitely specifying its shape, create a row vector</description>
|
---|
112 | /// </item>
|
---|
113 | /// <item>
|
---|
114 | /// <term>false (default)</term>
|
---|
115 | /// <description>When a vector is created without exlicitely specifying its shape, create a column vector</description>
|
---|
116 | /// </item></list>
|
---|
117 | /// </summary>
|
---|
118 | /// <remarks>This setting affects the way ILNumerics handles the default shape for vectors created. One example is <see cref="ILNumerics.ILMath.array{T}( T[])"/>,
|
---|
119 | /// where only the number of elements is given - but no size is specified. By default, ILNumerics will interpret the elements as targeting the <b>first</b>
|
---|
120 | /// dimension, ie. dimension #0. This will create a column vector. Setting this switch to 'true' will make ILNumerics to create a row vector in
|
---|
121 | /// such situations instead.</remarks>
|
---|
122 | public static bool CreateRowVectorsByDefault {
|
---|
123 | get {
|
---|
124 | return s_createRowVectorsByDefault;
|
---|
125 | }
|
---|
126 | set {
|
---|
127 | s_createRowVectorsByDefault = value;
|
---|
128 | }
|
---|
129 | }
|
---|
130 | /// <summary>
|
---|
131 | /// Upper limit of the range of array length to gather profiler information for
|
---|
132 | /// </summary>
|
---|
133 | public static int MemoryPoolProfileMaxLength {
|
---|
134 | get {
|
---|
135 | return s_memoryPoolProfileMaxLength;
|
---|
136 | }
|
---|
137 | set {
|
---|
138 | s_memoryPoolProfileMaxLength = value;
|
---|
139 | }
|
---|
140 | }
|
---|
141 | /// <summary>
|
---|
142 | /// Lower limit of the range of array length to gather profiler information for
|
---|
143 | /// </summary>
|
---|
144 | public static int MemoryPoolProfileMinLength {
|
---|
145 | get {
|
---|
146 | return s_memoryPoolProfileMinLength;
|
---|
147 | }
|
---|
148 | set {
|
---|
149 | s_memoryPoolProfileMinLength = value;
|
---|
150 | }
|
---|
151 | }
|
---|
152 | /// <summary>
|
---|
153 | /// If set to any non empty value, this setting triggers the memory pool profiler
|
---|
154 | /// </summary>
|
---|
155 | /// <remarks>Profiling the memory pool gives insights into those functions, which potentially
|
---|
156 | /// cause memory leaks in your application. It writes extensive stack trace information into the
|
---|
157 | /// logfile determined by this setting. It will contain the stack trace of any function, requesting
|
---|
158 | /// memory from the pool, which is never given back to the pool. Use this information in order to find and
|
---|
159 | /// correct those places - and increase stability and performance of your application. However,
|
---|
160 | /// make sure, this switch is cleared (or renamed) for production systems, since running the profiler
|
---|
161 | /// will diminish performance significantly.</remarks>
|
---|
162 | public static string MemoryPoolProfileFileName {
|
---|
163 | get {
|
---|
164 | return s_memoryPoolProfileFileName;
|
---|
165 | }
|
---|
166 | set {
|
---|
167 | s_memoryPoolProfileFileName = value;
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|
171 | /// <summary>
|
---|
172 | /// Gives the current setting for the reporting of runtime performance measures to the windows performance monitor (perfmon) (readonly)
|
---|
173 | /// </summary>
|
---|
174 | /// <remarks>Activating this switch requires administrative rights on each system the application is run - at least for the first time! This is
|
---|
175 | /// necessary in order to register the performance counters to the system. Afterwards, the application does not require administrative rights anymore.
|
---|
176 | /// <para>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
|
---|
177 | /// the feature is disabled by default. In order to enable it, a configuration variable named "ILNMeasurePerformanceAtRuntime" needs to be set in your
|
---|
178 | /// application configuration file.</para></remarks>
|
---|
179 | public static bool MeasurePerformanceAtRuntime {
|
---|
180 | get { return s_measurePerformanceAtRuntime; }
|
---|
181 | }
|
---|
182 |
|
---|
183 | /// <summary>
|
---|
184 | /// Determine the minimum length for arrays to be sorted via Quicksort algorithm, smaller arrays are sorted via insertion sort
|
---|
185 | /// </summary>
|
---|
186 | public static int MinimumQuicksortLength {
|
---|
187 | get { return s_minimumQuicksortLength; }
|
---|
188 | set { s_minimumQuicksortLength = value; }
|
---|
189 | }
|
---|
190 | /// <summary>
|
---|
191 | /// Maximum number of threads for parallel execution of internal functions in ILNumerics
|
---|
192 | /// </summary>
|
---|
193 | /// <remarks>
|
---|
194 | /// <para>In order to maximize execution speed of numerical algorithms, the value of <c>MaxNumberThreads</c> should be equal to the number
|
---|
195 | /// of <b>real</b> processor cores on the system. For processors utilizing <a href="http://en.wikipedia.org/wiki/Hyper-threading">Hyper-threading</a> the number on virtual cores
|
---|
196 | /// 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'
|
---|
197 | /// appearing e.g. in the windows task manager is misleading and the true number of independent cores should be used for <c>MaxNumberThreads</c> instead. Consult your proccessor vendor in order to find out, how many
|
---|
198 | /// independant cores your system utilizes.</para>
|
---|
199 | /// <para>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 <a href="http://ilnumerics.net/$Configuration.html">set manually</a> for
|
---|
200 | /// better processor utilization on multicore machines.</para>
|
---|
201 | /// <para>If your algorithm uses custom parallel execution models, it may
|
---|
202 | /// be necessary to set this value to '1'. ILNumerics will run single threaded than - leaving you the option to configure
|
---|
203 | /// the execution on parallel threads on your own.</para>
|
---|
204 | /// <para>The setting of this value also effects the corresponding value of any unmanaged optimized support library (e.g. MKL) internally used by ILNumerics.</para>
|
---|
205 | /// </remarks>
|
---|
206 | public static int MaxNumberThreads {
|
---|
207 | get { return s_maxNumberThreads; }
|
---|
208 | set {
|
---|
209 | if (value < 1)
|
---|
210 | throw new ILNumerics.Exceptions.ILArgumentException("number of worker threads must be greater than 0");
|
---|
211 | Misc.ILThreadPool.Pool.MaxNumberThreads = value - 1;
|
---|
212 | s_maxNumberThreads = value;
|
---|
213 | }
|
---|
214 | }
|
---|
215 | /// <summary>
|
---|
216 | /// Determine, if the current setting of <see cref="MaxNumberThreads"/> is the result of a custom configuration
|
---|
217 | /// </summary>
|
---|
218 | public static bool MaxNumberThreadsConfigured {
|
---|
219 | get { return s_maxNumberThreadsConfigured; }
|
---|
220 | private set { s_maxNumberThreadsConfigured = value; }
|
---|
221 | }
|
---|
222 |
|
---|
223 | /// <summary>
|
---|
224 | /// Threshold used to determine, if computations of O(n^3) built-in-functions are done in parallel on multicore machines
|
---|
225 | /// </summary>
|
---|
226 | public static int MinParallelElement3Count {
|
---|
227 | get { return s_minParallelElement3Count; }
|
---|
228 | set { s_minParallelElement3Count = value; }
|
---|
229 | }
|
---|
230 |
|
---|
231 | /// <summary>
|
---|
232 | /// Threshold used to determine, if computations of O(n^2) built-in-functions are done in parallel on multicore machines
|
---|
233 | /// </summary>
|
---|
234 | public static int MinParallelElement2Count {
|
---|
235 | get { return s_minParallelElement2Count; }
|
---|
236 | set { s_minParallelElement2Count = value; }
|
---|
237 | }
|
---|
238 |
|
---|
239 | /// <summary>
|
---|
240 | /// Threshold used to determine, if computations of O(n) built-in-functions are done in parallel on multicore machines
|
---|
241 | /// </summary>
|
---|
242 | public static int MinParallelElement1Count {
|
---|
243 | get { return s_minParallelElement1Count; }
|
---|
244 | set { s_minParallelElement1Count = value; }
|
---|
245 | }
|
---|
246 |
|
---|
247 | /// <summary>
|
---|
248 | /// Maximal recursion depth the quicksort can go. default: 100 (for array length up to 2^100)
|
---|
249 | /// </summary>
|
---|
250 | public static int MaxSafeQuicksortRecursionDepth {
|
---|
251 | get { return s_maxSafeQuicksortRecursionDepth; }
|
---|
252 | set { s_maxSafeQuicksortRecursionDepth = value; }
|
---|
253 | }
|
---|
254 |
|
---|
255 | /// <summary>
|
---|
256 | /// Controls implicit conversions from logical arrays to System.Boolean
|
---|
257 | /// </summary>
|
---|
258 | /// <remarks>This setting specifies, how logical arrays are converted to System.Boolean. Those
|
---|
259 | /// conversions are important, in order to simplify expressions like
|
---|
260 | /// <code>if (A > B) { ... }</code> on arrays A and B.
|
---|
261 | /// <para>Here, the comparison <code>A > B</code> creates a logical array of the same size than A and B. The logical array contains
|
---|
262 | /// the result of the elementwise 'greater than' comparison. This setting here controls, how that logical is converted
|
---|
263 | /// to a System.Boolean, in order to evaluate the 'if' condition. </para>
|
---|
264 | /// <para>The default is <c>LogicalConversionMode.NonScalarThrowsException</c>, which would cause an exception to be thrown in
|
---|
265 | /// the example above. Only scalar logical arrays can be used in such implicit conversions than.</para>
|
---|
266 | /// <para>In order to further simplify the syntax, the <c>LogicalConversionMode.ImplicitAllAll</c> setting can be used. The above expression
|
---|
267 | /// would evaluate to true, if <b>all</b> elements of B are greater than corresponding elements of A. This settings therefore
|
---|
268 | /// eases the syntax for most situations. However, since most comparison operators comply to the underlying <b>all</b> rule,
|
---|
269 | /// the '!=' (not equal to) operator does not - at least to the extend of common intuition. In an expression:
|
---|
270 | /// <code>if (A != B) { ... }</code> one would intuitively expect to execute the code block, if <b>at least one element</b> of A does not equal the corresponding element
|
---|
271 | /// of B. However, due to the <b>all</b> rule, this is not the case! In fact, the code would be executed only, if <b>all</b> elements would
|
---|
272 | /// evaluate to true. I.e. if no single pair of corresponding elements in A and B are equal. In order to
|
---|
273 | /// get the intuitively expected behavior, one would override this by:
|
---|
274 | /// <code>if (ILMath.any(A != B)) { ... } </code>
|
---|
275 | /// Since it may cause hard to find bugs, this setting should be used with care.</para></remarks>
|
---|
276 | public static LogicalConversionMode LogicalArrayToBoolConversion {
|
---|
277 | get { return s_logicalArrayToBoolConversion; }
|
---|
278 | set { s_logicalArrayToBoolConversion = value; }
|
---|
279 | }
|
---|
280 | /// <summary>
|
---|
281 | /// Determine, if main and worker threads should bind to constant cpus or not. The default is not to bind.
|
---|
282 | /// </summary>
|
---|
283 | /// <remarks>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
|
---|
284 | /// be used to make ILNumerics worker threads be affine to corresponding (native) threads.</remarks>
|
---|
285 | public static bool UseThreadAffinity {
|
---|
286 | get { return s_useThreadAffinity; }
|
---|
287 | set { s_useThreadAffinity = value; }
|
---|
288 | }
|
---|
289 | #endregion
|
---|
290 |
|
---|
291 | #region public interface
|
---|
292 | /// <summary>
|
---|
293 | /// (Re)load settings from the application configuration file
|
---|
294 | /// </summary>
|
---|
295 | public static void LoadDefaults() {
|
---|
296 |
|
---|
297 | tryLoadSetting<int>("ILNMinimumQuicksortLength", ref s_minimumQuicksortLength, int.Parse, 10);
|
---|
298 | if (!tryLoadSetting<int>("ILNMaxNumberThreads", ref s_maxNumberThreads, int.Parse, 2)) {
|
---|
299 | // determine number of threads in another way: here: hardcoded
|
---|
300 | if (Environment.ProcessorCount > 1 && !System.Diagnostics.Debugger.IsAttached)
|
---|
301 | s_maxNumberThreads = 2;
|
---|
302 | else
|
---|
303 | s_maxNumberThreads = 1;
|
---|
304 | MaxNumberThreadsConfigured = false;
|
---|
305 | // TODO: try to determine number of PHYSICAL cores automatically
|
---|
306 | // try to load number of physical cores rather than logical cores - utilize CPUID via native function pointer!
|
---|
307 | } else {
|
---|
308 | MaxNumberThreadsConfigured = true;
|
---|
309 | }
|
---|
310 | tryLoadSetting<int>("ILNMinParallelElement3Count", ref s_minParallelElement3Count, int.Parse, 500);
|
---|
311 | tryLoadSetting<int>("ILNMinParallelElement2Count", ref s_minParallelElement2Count, int.Parse, 1000);
|
---|
312 | tryLoadSetting<int>("ILNMinParallelElement1Count", ref s_minParallelElement1Count, int.Parse, (System.Environment.Is64BitProcess) ? 2000 : 2000);
|
---|
313 | tryLoadSetting<int>("ILNMaxSafeQuicksortRecursionDepth", ref s_maxSafeQuicksortRecursionDepth, int.Parse, 100);
|
---|
314 | tryLoadSetting<LogicalConversionMode>("ILNLogicalArrayToBoolConversion", ref s_logicalArrayToBoolConversion, logicalEnumParse, LogicalConversionMode.NonScalarThrowsException);
|
---|
315 | tryLoadSetting<string>("ILNMemoryPoolProfileFileName", ref s_memoryPoolProfileFileName, dummyStringCopy, "");
|
---|
316 | tryLoadSetting<int>("ILNMemoryPoolProfileMaxLength", ref s_memoryPoolProfileMaxLength, int.Parse, 500);
|
---|
317 | tryLoadSetting<int>("ILNMemoryPoolProfileMinLength", ref s_memoryPoolProfileMinLength, int.Parse, 500);
|
---|
318 | tryLoadSetting<int>("ILNMinElementLength4SystemArrayCopy", ref s_minElementLength4SystemArrayCopy, int.Parse, 50);
|
---|
319 | tryLoadSetting<bool>("ILNUseThreadAffinity", ref s_useThreadAffinity, bool.Parse, false);
|
---|
320 | tryLoadSetting<bool>("ILNCreateRowVectorsByDefault", ref s_createRowVectorsByDefault, bool.Parse, false);
|
---|
321 | tryLoadSetting<bool>("ILNAllowInArrayAssignments", ref s_allowInArrayAssignments, bool.Parse, true);
|
---|
322 | string configLicenseFilename = null, configLicenseResourceName = null;
|
---|
323 | tryLoadSetting<string>("ILNLicenseFilename", ref configLicenseFilename, dummyStringCopy, "ILNumerics.lic");
|
---|
324 | tryLoadSetting<string>("ILNLicenseResourceName", ref configLicenseResourceName, dummyStringCopy, "ILNumerics.lic");
|
---|
325 | tryLoadSetting<bool>("ILNMeasurePerformanceAtRuntime", ref s_measurePerformanceAtRuntime, bool.Parse, false);
|
---|
326 |
|
---|
327 | }
|
---|
328 | #endregion
|
---|
329 |
|
---|
330 | #region private helper
|
---|
331 | private static bool tryLoadSetting<T>(string settingsName, ref T obj, System.Converter<string, T> convert, T defaultValue) {
|
---|
332 | string value = System.Configuration.ConfigurationManager.AppSettings[settingsName];
|
---|
333 | T tmp;
|
---|
334 | if (!string.IsNullOrEmpty(value)) {
|
---|
335 | try {
|
---|
336 | tmp = convert(value); // may throws exception!
|
---|
337 | obj = tmp;
|
---|
338 | return true;
|
---|
339 | } catch (Exception exc) {
|
---|
340 | tmp = defaultValue;
|
---|
341 | throw new ILNumerics.Exceptions.ILArgumentException("Error reading default setting from application configuration, appsettings section: Invalid value for: '" + settingsName + "'", exc);
|
---|
342 | }
|
---|
343 | } else {
|
---|
344 | obj = defaultValue;
|
---|
345 | return false;
|
---|
346 | }
|
---|
347 | }
|
---|
348 | internal static string dummyStringCopy(string val) { return val.Trim(); }
|
---|
349 | internal static LogicalConversionMode logicalEnumParse(string val) {
|
---|
350 | LogicalConversionMode ret;
|
---|
351 | if (Enum.TryParse<LogicalConversionMode>(val, out ret)) {
|
---|
352 | return ret;
|
---|
353 | }
|
---|
354 | throw new ILNumerics.Exceptions.ILArgumentException("The configuration value for 'ILNLogicalArrayToBoolConversion' is not valid.");
|
---|
355 | }
|
---|
356 | #endregion
|
---|
357 | }
|
---|
358 | }
|
---|